Win32 工具栏下拉按钮消息处理

Win32 Toolbar Dropdown Button Message Handling

本文关键字:按钮 消息处理 工具栏 Win32      更新时间:2023-10-16

我的应用程序中有一个窗口的工具栏。我已经阅读了MSDN文档,可以处理命令和通知消息。我的问题是附加到工具栏上的按钮的下拉菜单。菜单项将打开模式对话框,并等待用户完成设置更改。但是,在用户单击"确定"或"取消"焦点后,工具栏仍然以鼠标左键已按下的印象,因此每次我将鼠标拖动到单击的工具栏按钮上时,该按钮都会处于"按钮已选中"状态并"似乎"被按下。

问题是否与鼠标事件的跟踪有关?

以下是窗口进程中的通知消息处理:

case WM_NOTIFY:
        {
            LPNMHDR lpnm = ( ( LPNMHDR )lParam );
            LPNMTOOLBAR lpnmTB = ( ( LPNMTOOLBAR )lParam );
            switch( lpnm->code )
            {
            case TBN_DROPDOWN:
                {
                    // Get the coordinates of the button.
                    RECT rc;
                    SendMessage( lpnmTB->hdr.hwndFrom, TB_GETRECT, ( WPARAM )lpnmTB->iItem, ( LPARAM )&rc );
                    // Convert to screen coordinates.            
                    MapWindowPoints( lpnmTB->hdr.hwndFrom, HWND_DESKTOP, ( LPPOINT )&rc, 2 );                         
                    // handle dropdown menus
                    return HandleTexEditDropdown( hWnd, lpnmTB, rc );
                }
            default:
                break;
            }
            break;
        }

下面是句柄 TexEditDropdown():

LRESULT CALLBACK CWindowManager::HandleTexEditDropdown( HWND hWnd, LPNMTOOLBAR lpnm, RECT &rc )
{
    HRESULT hr = S_OK;
    switch( lpnm->iItem )
    {
    case IDM_EDITTEXTURE_FILL:
        {
            // Get the menu.
            HMENU hMenuLoaded = LoadMenu( GetModuleHandle( NULL ), MAKEINTRESOURCE( IDR_BUCKETFILL ) ); 
            // Get the submenu for the first menu item.
            HMENU hPopupMenu = GetSubMenu( hMenuLoaded, 0 );
            // Set up the pop-up menu.
            // In case the toolbar is too close to the bottom of the screen, 
            // set rcExclude equal to the button rectangle and the menu will appear above 
            // the button, and not below it.
            TPMPARAMS tpm;
            tpm.cbSize    = sizeof( TPMPARAMS );
            tpm.rcExclude = rc;
            // Show the menu and wait for input. 
            // If the user selects an item, its WM_COMMAND is sent.
            INT nCmd = TrackPopupMenuEx( hPopupMenu, 
                TPM_LEFTALIGN | TPM_LEFTBUTTON | TPM_VERTICAL | TPM_RETURNCMD, 
                rc.left, rc.bottom, hWnd, &tpm );
            DestroyMenu( hMenuLoaded );
            switch( nCmd )
            {
            case IDM_BUCKETFILLSETTINGS:
                DialogBox( GetModuleHandle( NULL ), 
                    MAKEINTRESOURCE( IDD_TEXEDITBUCKETFILL ), 
                    hWnd, 
                    ( DLGPROC )TexEditSettingsProc );
                break;
            default:
                return 0;
            }
            SendMessage( ( HWND )lpnm->hdr.hwndFrom, TB_MARKBUTTON, lpnm->iItem, MAKELPARAM( FALSE, 0 ) );
            UpdateWindow( hWnd );
            SetStateChange();
            return 1;
        }
    case IDM_EDITTEXTURE_RECOVER:
        {
            // Get the menu.
            HMENU hMenuLoaded = LoadMenu( GetModuleHandle( NULL ), MAKEINTRESOURCE( IDR_RECOVER ) ); 
            // Get the submenu for the first menu item.
            HMENU hPopupMenu = GetSubMenu( hMenuLoaded, 0 );
            // Set up the pop-up menu.
            // In case the toolbar is too close to the bottom of the screen, 
            // set rcExclude equal to the button rectangle and the menu will appear above 
            // the button, and not below it.
            TPMPARAMS tpm;
            tpm.cbSize    = sizeof( TPMPARAMS );
            tpm.rcExclude = rc;
            // Show the menu and wait for input. 
            // If the user selects an item, its WM_COMMAND is sent.
            INT nCmd = TrackPopupMenuEx( hPopupMenu, 
                TPM_LEFTALIGN | TPM_LEFTBUTTON | TPM_VERTICAL | TPM_RETURNCMD, 
                rc.left, rc.bottom, hWnd, &tpm );
            DestroyMenu( hMenuLoaded );
            switch( nCmd )
            {
            case IDM_RECOVERFILE:
                {
                    WCHAR wcs[ MAX_PATH ] = L"",
                        wcsFiletype[ MAX_PATH ] = L"",
                        wcsFilename[ MAX_PATH ] = L"";
                    D3DXIMAGE_INFO info;
                    // get currently loaded image info
                    if( FAILED( hr = CTextureEditor::GetImageInfo( &info ) ) )
                    {
                        DebugStringDX( ClassName, "Failed to CTextureEditor::GetImageInfo() at AuxiliaryViewportProcess()", __LINE__, hr );
                        break;
                    }
                    if( !CTextureEditor::CatImageFileType( info.ImageFileFormat, wcsFiletype ) )
                    {
                        DebugStringDX( ClassName, "Invalid image filetype at AuxiliaryViewportProcess()", __LINE__, hr );
                        break;
                    }
                    wsprintf( wcs, L"GDEImage Filetype (*%s)", wcsFiletype );
                    memcpy( &wcs[ 26 ], L"*", sizeof( WCHAR ) );
                    memcpy( &wcs[ 27 ], wcsFiletype, 4 * sizeof( WCHAR ) );
                    // Declare and initialize an OPENFILENAME struct to use for OpenFile Dialog
                    OPENFILENAME ofn;
                    ZeroMemory( ( void* )&ofn, sizeof( OPENFILENAME ) );
                    ofn.lStructSize = sizeof( ofn ); // SEE NOTE BELOW
                    ofn.hwndOwner = hWnd;
                    ofn.lpstrTitle = L"Recover Image From File";
                    ofn.lpstrFilter = wcs;
                    ofn.lpstrFile = wcsFilename;
                    ofn.nMaxFile = MAX_PATH;
                    ofn.Flags = OFN_EXPLORER | OFN_FILEMUSTEXIST | OFN_HIDEREADONLY;
                    ofn.lpstrDefExt = L"image file";
                    ofn.lpstrInitialDir = app.GetBinDirectory();
                    // OpenFile Dialog
                    if( GetOpenFileName( &ofn ) )
                    {                                       
                        if( FAILED( hr = CTextureEditor::Recover( 0, wcsFilename ) ) )
                        {
                            DebugStringDX( ClassName, "Failed to CTextureEditor::Recover() at AuxiliaryViewportProc()", __LINE__, hr );
                            break;
                        }
                    }
                    break;
                }
            default:
                return 0;
            }
            SendMessage( ( HWND )lpnm->hdr.hwndFrom, TB_MARKBUTTON, lpnm->iItem, MAKELPARAM( FALSE, 0 ) );
            UpdateWindow( hWnd );
            SetStateChange();
            return 1;
        }
    default:
        return 0;
    }
    return 0;
}

我认为TBN_DROPDOWN的返回值不正确 - 您返回1映射到TBDDRET_NODEFAULT意思是"下拉列表未处理",您需要返回TBDDRET_DEFAULTTBDDRET_TREATPRESSED