我试图将EDIT控件添加到用作自定义组合框控件的下拉菜单的窗口。最初,此下拉窗口是作为桌面的子(WS_CHILD
)窗口实现的,类似于真实组合框使用的“ ComboLbox”窗口。这工作得很好,但是当将EDIT窗口放到这样的下拉窗口中时,它似乎只是拒绝接受焦点。即例如,它已启用并响应鼠标右键单击,但是单击它或调用SetFocus()
失败(后者将最后一个错误设置为ERROR_INVALID_PARAMETER
)。
因此,并且由于在许多示例(包括Raymond Chen的fakemenu sample)中实现了自定义弹出窗口的方式,我将下拉实现更改为使用WS_POPUP
,并且具有主应用程序窗口作为所有者。这是一个已知的问题,当显示弹出窗口时会从所有者窗口中窃取激活,但是可以通过从MA_NOACTIVATE
处理程序中返回WM_MOUSEACTIVATE
来弹出窗口来解决此问题,并且在开始时确实工作良好,即弹出窗口显示时,所有者窗口保持激活状态。但是,一旦我在弹出窗口中单击EDIT控件,它就会从其默认窗口proc调用SetFocus()
来将焦点设置为自身,这将停用父窗口。
我的问题是如何防止这种情况发生?我知道可以做到这一点,因为WinForms ToolStripManager设法允许在下拉列表中编辑文本而无需停用父窗口,并且它对弹出窗口也使用WS_POPUP
样式。但是它是怎么做到的?
答案 0 :(得分:2)
评论中提出了一种解决方案“通过处理WM_NCACTIVATE
防止主机窗口明显不活动” 此操作应如以下示例所示。
打开菜单窗口时,主窗口(HostProc
)将收到WM_NCACTIVATE
消息。主机将寻找"menuclass"
,如果找到菜单类,则主机将返回DefWindowProc(hwnd, WM_NCACTIVATE, TRUE, lparam);
以防止主机窗口的标题栏被绘制为非活动状态。
您还需要在伪菜单窗口中处理WM_NCACTIVATE
。当菜单窗口失去焦点时,WM_NCACTIVATE
收到MenuProc
,此时菜单可以自行关闭。
#include <windows.h>
const wchar_t* menuclass = L"menuclass";
LRESULT CALLBACK MenuProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
{
switch(msg)
{
case WM_CREATE:
CreateWindow(L"Edit", NULL, WS_CHILD | WS_VISIBLE | WS_BORDER, 10, 10, 160, 30,
hwnd, NULL, NULL, NULL);
break;
case WM_NCACTIVATE:
{
if(!wparam)
{
//close the menu if its losing focus
PostMessage(hwnd, WM_CLOSE, 0, 0);
//tell parent to paint inactive, if user clicked on a different program
POINT pt;
GetCursorPos(&pt);
HWND hit = WindowFromPoint(pt);
HWND hparent = GetParent(hwnd);
if(hit != hparent && !IsChild(hparent, hit))
DefWindowProc(hparent, WM_NCACTIVATE, FALSE, 0);
}
break;
}
case WM_LBUTTONDOWN:
PostMessage(hwnd, WM_CLOSE, 0, 0);
break;
//also handles other mouse/key messages associated with a menu...
}
return DefWindowProc(hwnd, msg, wparam, lparam);
}
LRESULT CALLBACK HostProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
{
switch(msg)
{
case WM_NCACTIVATE:
//paint the window as active when custom menu starts
if(!wparam && FindWindow(menuclass, NULL))
return DefWindowProc(hwnd, WM_NCACTIVATE, TRUE, lparam);
break;
case WM_RBUTTONUP:
{
//show the custom menu
POINT pt;
GetCursorPos(&pt);
CreateWindow(menuclass, NULL, WS_VISIBLE | WS_POPUP | WS_BORDER,
pt.x, pt.y, 200, 400, hwnd, 0, 0, 0);
return 0;
}
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hwnd, msg, wparam, lparam);
}
int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE, LPTSTR, int)
{
WNDCLASSEX wcex = { sizeof(WNDCLASSEX) };
wcex.hInstance = hInstance;
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.lpfnWndProc = HostProc;
wcex.lpszClassName = L"hostwnd";
RegisterClassEx(&wcex);
wcex.lpfnWndProc = MenuProc;
wcex.lpszClassName = menuclass;
RegisterClassEx(&wcex);
CreateWindow(L"hostwnd", L"Right click for menu ...",
WS_VISIBLE | WS_OVERLAPPEDWINDOW, 0, 0, 600, 400, 0, 0, hInstance, 0);
MSG msg;
while(GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return (int)msg.wParam;
}