安装程序:几年前,我们开发了一个很好的C ++跨平台,可以pipe理在Mac OS X Windows之间编写通用代码源的许多问题。 (我们不会陷入这种方法的严重缺陷 – 我们在1993年开发了这个方法!)。
为了简化可重用组件的开发,我们最近添加了一个“窗格”概念来包含多个控件和用户项目,基本上处理了绘图和其他事件(如按键和鼠标点击)的层次性。
我们在Mac OS X(碳)方面成功地构build了这种方法。 然而,试图将这种方法转移到Windows(XP SP3及更高版本)导致了无数的混乱问题:不停地重新绘制窗口内容,事件没有传递到我们的“窗格”中。
在Windows中,每个窗格都转换成一个“窗口”,我怀疑这可能是问题的根源:将某个封闭项目下的项目重叠可能会干扰绘图和事件传播。
有没有一种可接受的方法来编程地将控件添加到分组层次结构中? 或者是否有具体的标志,必须设置来完成这个?
(注意:尽pipe我们目前与XP SP3兼容,但我们不需要 – 我们可以将最低操作系统定位为Windows 7。目前我们正在使用VS 2010进行开发)
斯蒂芬
关于它通常如何工作的简单分解。
当您创建包含子级的父窗口(以下称为“窗格”)时,闪烁通常是由处理WM_ERASEBKGND消息的父窗口的窗口过程引起的,并且在指示子级之前在其所有子级上绘制“顶部”重新绘制自己。
正如Nik Bougalis所说,在创建父窗格时,如果使用CS_CLIPCHILDREN样式创建它,则不会在窗格的任何子区域(区域或区域)的边界内出现由DefWindowProc()执行的绘制。 因此,子窗口或控件所占据的“屏幕空间”完全是子控件本身的责任。
对于大多数标准的Windows控件来说,这很好。 这将解决闪烁的问题。
至于消息:子窗口每个获得自己的WM_MOUSEMOVE,WM_LBUTTONDOWN,WM_KEYDOWN(等)消息。 Windows将这些消息发送到具有焦点的实际窗口。
如果你想让父窗口得到这些,你将不得不做一些子窗口(控件)的子窗口过程。 然后在你的新的WndProc()中,你将有一个你想要捕获的消息的处理程序,并将它们发送到父窗格的HWND。
这里是一个简单的控制嵌入控制的例子。 它显示子分类和传递消息上游。
在蓝色的“窗格”中右击两个孩子中的任意一个,编辑控件或按钮!
#define _CRT_SECURE_NO_WARNINGS #include <Windows.h> #include <stdio.h> LRESULT __stdcall WndProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam ); LRESULT __stdcall FrameProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam ); LRESULT __stdcall SubClassProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam ); int __stdcall WinMain(HINSTANCE hInstance, HINSTANCE hpi, LPSTR lpcl, int ncs) { WNDCLASSEX wcex; MSG msg; HWND hWnd=0, hFrame=0, hEdit=0, hButton=0, hCheckBox=0; ATOM ca=0, caframe=0; RECT cr; HBRUSH framecolor; int cx=0; char *ptr=(char *)&wcex; int i =0; for (;i<sizeof(wcex);i++) { ptr[i]=0; } wcex.cbSize=sizeof(wcex); wcex.hbrBackground = (HBRUSH) COLOR_WINDOW; wcex.hCursor = LoadCursor(0, IDC_ARROW); wcex.lpfnWndProc = &WndProc; wcex.lpszClassName = "mywnd"; wcex.hInstance = hInstance; wcex.style = CS_HREDRAW|CS_VREDRAW; ca = RegisterClassEx(&wcex); for (i=0;i<sizeof(wcex);i++) { ptr[i]=0; } wcex.cbSize=sizeof(wcex); framecolor = CreateSolidBrush(0xFFA100); wcex.hbrBackground = (HBRUSH) framecolor; wcex.hCursor = LoadCursor(0, IDC_ARROW); wcex.lpfnWndProc = &FrameProc; wcex.lpszClassName = "myframe"; wcex.hInstance = hInstance; wcex.style = CS_HREDRAW|CS_VREDRAW; caframe = RegisterClassEx(&wcex); hWnd = CreateWindowExA(0, (LPCSTR)ca, "My Window", WS_CLIPCHILDREN|WS_VISIBLE|WS_SYSMENU|WS_SIZEBOX, 100, 100, 500, 500, 0, 0, hInstance, 0); GetClientRect(hWnd, &cr); hFrame = CreateWindowExA(0, (LPCSTR)caframe, "", WS_VISIBLE|WS_BORDER|WS_CHILD|WS_CLIPCHILDREN, 10, 10, ((cr.right-cr.left)-20), ((cr.bottom-cr.top)-20), hWnd, (HMENU) 1, hInstance, 0); cx = ((cr.right-cr.left)-20)/2; hEdit = CreateWindowExA(0, "Edit", "Edit Control", WS_CHILD|WS_VISIBLE|WS_BORDER, 10, 10, cx, 20, hFrame, (HMENU) 2, hInstance, 0); hButton = CreateWindowExA(0, "Button", "Click Me!", WS_CHILD|WS_VISIBLE, cx+20, 10, 70, 20, hFrame, (HMENU) 3, hInstance, 0); /* Sub-Class the children */ SetWindowLongPtr(hEdit, GWLP_USERDATA, GetWindowLongPtr(hEdit, GWLP_WNDPROC)); SetWindowLongPtr(hButton, GWLP_USERDATA, GetWindowLongPtr(hButton, GWLP_WNDPROC)); SetWindowLongPtr(hEdit, GWLP_WNDPROC, (LONG)&SubClassProc); SetWindowLongPtr(hButton, GWLP_WNDPROC, (LONG)&SubClassProc); if (!hWnd) { return -1; } while ( GetMessage(&msg, 0, 0, 0) ) { TranslateMessage(&msg); DispatchMessage(&msg); } DestroyWindow(hWnd); DeleteObject(framecolor); return 0; } LRESULT __stdcall WndProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam ) { RECT rc; switch (uMsg) { case WM_WINDOWPOSCHANGING: GetClientRect(hWnd, &rc); SetWindowPos(GetDlgItem(hWnd, 1), 0, 0, 0, ((rc.right-rc.left)-20), ((rc.bottom-rc.top)-20), SWP_NOZORDER|SWP_NOMOVE); break; case WM_CLOSE: PostQuitMessage(0); break; default: break; } return DefWindowProc(hWnd, uMsg, wParam, lParam); } LRESULT __stdcall FrameProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam ) { PAINTSTRUCT ps; WINDOWPOS *wp=0; POINT p; short wmid=0, wmevent=0; char message[300]; switch (uMsg) { case WM_WINDOWPOSCHANGING: wp = (WINDOWPOS *)lParam; SetWindowPos(GetDlgItem(hWnd, 2), 0, 0, 0, (wp->cx/2), 20, SWP_NOMOVE|SWP_NOZORDER); SetWindowPos(GetDlgItem(hWnd, 3), 0, (wp->cx/2)+20, 10, 0, 0, SWP_NOSIZE|SWP_NOZORDER); break; case WM_RBUTTONDOWN: px = (lParam & 0x0000ffff); py = (lParam >> 16 ); sprintf(message, "The \"frame\" got a WM_RBUTTONDOWN message!\nx: %i\ny: %i\n", px, py); MessageBox(GetParent(hWnd), message, "Message", MB_ICONINFORMATION); break; case WM_COMMAND: wmid = (wParam & 0x0000ffff); wmevent = wParam>>16; switch (wmid) { case 3: if (wmevent==BN_CLICKED) { MessageBox(GetParent(hWnd), "You clicked my button!", "Notice", MB_OK); } break; default: break; } break; case WM_PAINT: break; default: break; } return DefWindowProc(hWnd, uMsg, wParam, lParam); } LRESULT __stdcall SubClassProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam ) { WNDPROC wp=0; POINT p; HWND hParent=0; char message[300]; wp = (WNDPROC)GetWindowLongPtr(hWnd, GWLP_USERDATA); if (!wp) { return DefWindowProc(hWnd, uMsg, wParam, lParam); } if (uMsg==WM_RBUTTONDOWN) { px = (lParam & 0x0000ffff); py = (lParam >> 16 ); sprintf(message, "Right-Click in control!\nx: %i\ny: %i\n\nNow, we'll convert this to the coordinates of the frame and pass the message up-stream!", px, py); hParent = GetParent(hWnd); MessageBox(GetParent(hParent), message, "Message", MB_ICONINFORMATION); ClientToScreen(hWnd, &p); ScreenToClient(hParent, &p); SendMessage(hParent, WM_RBUTTONDOWN, wParam, MAKELPARAM(px, py)); } return CallWindowProc( wp, hWnd, uMsg, wParam, lParam); }
大多数本地Windows控件自动通过WM_COMMAND或WM_NOTIFY消息通知他们的父母。 就像在编辑控件中更改文本一样。 它发送一个WM_COMMAND消息给它的包含A的父窗口。它是句柄B.它是标识符C.通知代码(event),在这种情况下是EN_CHANGE。
所以你可以拦截这些消息并通过SendMessage()将它们转发到任何地方。
当您进入自定义绘图控件时,您需要了解以下内容:
内存设备上下文基本上是一个隐形的地方,您可以执行您的绘图操作。 像bkausbk说,一个缓冲区。 在我写的程序中,我需要添加一点点,我绘制到内存设备上下文,然后在WM_PAINT事件(从系统)中使用BitBlt()复制所有我的窗口和他们的孩子已经吸引到要显示的窗口的设备上下文中。
PAINTSTRUCT ps; case WM_PAINT: BeginPaint(hWnd, &ps); BitBlt(ps.hdc, 0, 0, cx, cy, hMemDC, 0, 0, SRCCOPY); EndPaint(hWnd &ps);
无论如何,有很多东西需要了解,但是我希望上面的小程序可以帮助你,并为你提供一个模板。