在纯 WinAPI GUI 应用程序中创建子 window 的子控件的最佳位置在哪里?
Where is the best place to create a child control of a child window in a pure WinAPI GUI App?
我正在开发仅限 WinAPI 的应用程序。我想创建一个 STATIC child window,它将用作子控件的 "container"。在我目前找到的示例中,"container" window 是在主 window 过程中捕获 WM_CREATE 的。我认为创建子 window 的子控件的最佳位置是捕获子 window 的 WM_CREATE。为此,我首先需要子类 window 指向新的 window 过程。问题是 window 是在它被子类化之前创建的,因此 WM_CREATE 被发送到原始过程而不是我的用户创建的过程。我当然可以在主 window 过程中创建子静态 window 之后创建子控件,但我认为这不是最好的方法。什么是最好的选择?
工作示例代码:
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_CREATE:
{
HWND hContainer = CreateWindow(WC_STATIC, L"Container", WS_CHILD, 0, 0, 100, 50, hWnd, (HMENU)ID_CONTAINER, NULL, NULL);
WNDPROC wpOldProc = (WNDPROC)SetWindowLongPtr(hContainer, GWLP_WNDPROC, (LONG_PTR)ChildWindowProc);
HWND hButton = CreateWindow(WC_BUTTON, L"Button", WS_CHILD | BS_PUSHBUTTON, 0, 0, 20, 10, hContainer, (HMENU)ID_BUTTON, NULL, NULL); // This works well
}
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
INT_PTR CALLBACK ChildWindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_CREATE:
{
// HWND hButton = CreateWindow(WC_BUTTON, L"Button", WS_CHILD | BS_PUSHBUTTON, 0, 0, 20, 10, hContainer, (HMENU)ID_BUTTON, NULL, NULL);
// This point is never reached because the WM_CREATE message is sent before subclassing of the window
}
break;
default:
break;
}
return CallWindowProc(gsHdl.wpTE, hWnd, message, wParam, lParam);
}
这里的主要原则是关注点分离:window 通常会创建其子项以响应其 WM_CREATE 消息,如:
这确保了 window "owns" 其子项的创建。它还保证当父级 window 直接由类名创建时,所有子级都会自动创建。最后,因为 WM_CREATE 在 window 被创建 visible/painted 之前发送,它确保子 windows 在 window 第一次创建时被创建画了。
当使用 child windows 来组织 child windows 时,很多这些考虑都会消失:- 如果你正在做一个适当的抽象控制 window 那是一回事,但是如果你只是在安排一些相对标准的 windows 控件,你希望主要的 window 能够与之交互然后深层层次结构导航很烦人,鼠标和绘画的方式有些奇怪,你可能想要将容器及其子项实际安排在 "wrong" z-order 中,如果将它们严格安排为 child/parents.
则无法实现
也就是说创建静态 window 并在后续行中使用返回的 HWND 作为父级 window 没有任何问题 - 特别是如果这样可以减少 [=30] 的数量=] 类,代码行/创建卷积 - 并简化父 windows 与其控件的关系。
在 WM_CREATE
消息下创建 sub-windows/controls 确保 sub-windows/controls 在成功 window 创建后创建,并且所有 sub-windows/sub-controls 在创建消息时自动创建主要 window.
不过我觉得和下面的区别不大:
HWND hContainer = CreateWindow (WC_STATIC, L "Container", WS_CHILD, 0, 0, 100, 50, hWnd, (HMENU) ID_CONTAINER, NULL, NULL);
if(hContainer)
{
HWND hButton = CreateWindow (WC_BUTTON, L "Button", WS_CHILD | BS_PUSHBUTTON, 0, 0, 20, 10, hContainer, (HMENU) ID_BUTTON, NULL, NULL);
}
同时保证了创建顺序和前置条件。
如果您确实需要在标准 windows 控件中修改 WinProc
和捕获 WM_CREATE
消息,SetWindowsLongPtr
不符合您的要求。在创建 "Container" 之前使用 SetClassLongPtr
。
我正在开发仅限 WinAPI 的应用程序。我想创建一个 STATIC child window,它将用作子控件的 "container"。在我目前找到的示例中,"container" window 是在主 window 过程中捕获 WM_CREATE 的。我认为创建子 window 的子控件的最佳位置是捕获子 window 的 WM_CREATE。为此,我首先需要子类 window 指向新的 window 过程。问题是 window 是在它被子类化之前创建的,因此 WM_CREATE 被发送到原始过程而不是我的用户创建的过程。我当然可以在主 window 过程中创建子静态 window 之后创建子控件,但我认为这不是最好的方法。什么是最好的选择?
工作示例代码:
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_CREATE:
{
HWND hContainer = CreateWindow(WC_STATIC, L"Container", WS_CHILD, 0, 0, 100, 50, hWnd, (HMENU)ID_CONTAINER, NULL, NULL);
WNDPROC wpOldProc = (WNDPROC)SetWindowLongPtr(hContainer, GWLP_WNDPROC, (LONG_PTR)ChildWindowProc);
HWND hButton = CreateWindow(WC_BUTTON, L"Button", WS_CHILD | BS_PUSHBUTTON, 0, 0, 20, 10, hContainer, (HMENU)ID_BUTTON, NULL, NULL); // This works well
}
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
INT_PTR CALLBACK ChildWindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_CREATE:
{
// HWND hButton = CreateWindow(WC_BUTTON, L"Button", WS_CHILD | BS_PUSHBUTTON, 0, 0, 20, 10, hContainer, (HMENU)ID_BUTTON, NULL, NULL);
// This point is never reached because the WM_CREATE message is sent before subclassing of the window
}
break;
default:
break;
}
return CallWindowProc(gsHdl.wpTE, hWnd, message, wParam, lParam);
}
这里的主要原则是关注点分离:window 通常会创建其子项以响应其 WM_CREATE 消息,如:
这确保了 window "owns" 其子项的创建。它还保证当父级 window 直接由类名创建时,所有子级都会自动创建。最后,因为 WM_CREATE 在 window 被创建 visible/painted 之前发送,它确保子 windows 在 window 第一次创建时被创建画了。
当使用 child windows 来组织 child windows 时,很多这些考虑都会消失:- 如果你正在做一个适当的抽象控制 window 那是一回事,但是如果你只是在安排一些相对标准的 windows 控件,你希望主要的 window 能够与之交互然后深层层次结构导航很烦人,鼠标和绘画的方式有些奇怪,你可能想要将容器及其子项实际安排在 "wrong" z-order 中,如果将它们严格安排为 child/parents.
则无法实现也就是说创建静态 window 并在后续行中使用返回的 HWND 作为父级 window 没有任何问题 - 特别是如果这样可以减少 [=30] 的数量=] 类,代码行/创建卷积 - 并简化父 windows 与其控件的关系。
在 WM_CREATE
消息下创建 sub-windows/controls 确保 sub-windows/controls 在成功 window 创建后创建,并且所有 sub-windows/sub-controls 在创建消息时自动创建主要 window.
不过我觉得和下面的区别不大:
HWND hContainer = CreateWindow (WC_STATIC, L "Container", WS_CHILD, 0, 0, 100, 50, hWnd, (HMENU) ID_CONTAINER, NULL, NULL);
if(hContainer)
{
HWND hButton = CreateWindow (WC_BUTTON, L "Button", WS_CHILD | BS_PUSHBUTTON, 0, 0, 20, 10, hContainer, (HMENU) ID_BUTTON, NULL, NULL);
}
同时保证了创建顺序和前置条件。
如果您确实需要在标准 windows 控件中修改 WinProc
和捕获 WM_CREATE
消息,SetWindowsLongPtr
不符合您的要求。在创建 "Container" 之前使用 SetClassLongPtr
。