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

标签 c++ winapi notifications message

我的应用程序中有一个窗口工具栏。我读过 MSDN docs 并且可以处理命令和通知消息。我的问题是下拉菜单附加到工具栏上的按钮。菜单项打开模态对话框并等待用户完成设置更改。在用户单击“确定”或“取消”后,焦点返回到主窗口,然而,工具栏仍然给人留下鼠标左键按下的印象,所以每次我将鼠标拖到被单击的工具栏按钮上时,按钮都会占用“按钮已选中”状态并且“看起来”已被按下。

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

这是窗口过程中的通知消息处理:

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

关于c++ - Win32 工具栏下拉按钮消息处理,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21009420/

相关文章:

c++ - OpenGL 纹理格式的颜色错误

windows - Windows 中的 "Job"(子进程)是什么,何时使用它?

java - 当我的闹钟触发 onReceive() 时,通知未显示

ios - 当通知超过 64 个限制时如何在 iOS 中安排更多本地通知

java - 如何找到杀死正在运行的 java VM 的进程

C++ 在虚方法中使用捕获 lambda

c# - 如何在.net框架上使用vst sdk

c++ - 如何从已经运行的 GUI 应用程序中启动带有 GUI 的可执行文件

c++ - GetDiBits:BITMAPINFOHEADER 中传递的不同维度

c++ - 判断当前字体是否支持 unicode 字符的简便方法?