windows – 如何创建Win32控件以包含其他Win32控件?
设置:几年前,我们开发了一个很好的C跨平台,它管理了许多在Mac OS X
Windows之间编写公共代码源的问题. (我们不会进入这种方法的巨大缺点 – 我们在1993年开发了这个!).
为了简化可重用组件的开发,我们最近添加了一个“窗格”概念来包含多个控件和用户项,主要处理绘图和其他事件的分层特性,例如击键和鼠标点击. 我们在Mac OS X(Carbon)方面成功构建了这种方法.然而,试图将这种方法转移到Windows(XP SP3及更高版本)已经导致了无数的混乱问题:不间断地重新绘制窗口内容,并且事件没有传递到我们的“窗格”中. 在Windows上,每个窗格都转换为“窗口”,我怀疑这可能是问题的根源:重叠“封闭”项目下面的项目可能会干扰绘图和事件传播. 是否有可接受的方法以编程方式将控件添加到分组层次结构中?或者是否有必须设置的特定FLAG来完成此任务? (注意:虽然我们目前与XP SP3兼容,但我们不需要 – 我们可以将最低操作系统定位为Windows 7.我们目前正在开发VS 2010) 斯蒂芬 解决方法
关于它通常如何工作的简单细分.
当您创建包含子项的父窗口(以下称为“窗格”)时,闪烁通常是由处理WM_ERASEBKGND消息的父窗口的窗口过程引起的,并在指示子项之前在其所有子项的“顶部”上绘制重绘自己. 正如Nik Bougalis所说,在创建父窗格时,如果使用CS_CLIPCHILDREN样式创建它,则DefWindowProc()不会在任何窗格的子边界(rects或region)的边界内发生绘制.因此,子窗口或控件占用的“屏幕空间”完全是子控件本身的责任. 对于大多数标准Windows控件,这很好.这将解决闪烁问题. 至于消息: 如果你想让父窗口得到这些,你将不得不做一些事情,称子窗口(控件)的窗口过程的子类.然后在新的WndProc()中,您将拥有要捕获的消息的处理程序,并将它们发送到父窗格的HWND. 这是一个在控件中嵌入控件的简单工作示例.它显示了子类并将消息传回上游. 右键单击两个孩子中的任何一个,EDIT控件或BUTTON,在蓝色的“窗格”中! #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,LPARAM lParam ); LRESULT __stdcall SubClassProc( HWND hWnd,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,500,hInstance,0); GetClientRect(hWnd,&cr); hFrame = CreateWindowExA(0,(LPCSTR)caframe,"",WS_VISIBLE|WS_BORDER|WS_CHILD|WS_CLIPCHILDREN,10,((cr.right-cr.left)-20),((cr.bottom-cr.top)-20),hWnd,(HMENU) 1,0); cx = ((cr.right-cr.left)-20)/2; hEdit = CreateWindowExA(0,"Edit","Edit Control",WS_CHILD|WS_VISIBLE|WS_BORDER,cx,20,hFrame,(HMENU) 2,0); hButton = CreateWindowExA(0,"Button","Click Me!",WS_CHILD|WS_VISIBLE,cx+20,70,(HMENU) 3,0); /* Sub-Class the children */ SetWindowLongPtr(hEdit,GWLP_USERDATA,GetWindowLongPtr(hEdit,GWLP_WNDPROC)); SetWindowLongPtr(hButton,GetWindowLongPtr(hButton,GWLP_WNDPROC)); SetWindowLongPtr(hEdit,GWLP_WNDPROC,(LONG)&SubClassProc); SetWindowLongPtr(hButton,(LONG)&SubClassProc); if (!hWnd) { return -1; } while ( GetMessage(&msg,0) ) { TranslateMessage(&msg); DispatchMessage(&msg); } DestroyWindow(hWnd); DeleteObject(framecolor); return 0; } LRESULT __stdcall WndProc( HWND hWnd,LPARAM lParam ) { RECT rc; switch (uMsg) { case WM_WINDOWPOSCHANGING: GetClientRect(hWnd,&rc); SetWindowPos(GetDlgItem(hWnd,1),((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,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),(wp->cx/2),SWP_NOMOVE|SWP_NOZORDER); SetWindowPos(GetDlgItem(hWnd,3),(wp->cx/2)+20,SWP_NOSIZE|SWP_NOZORDER); break; case WM_RBUTTONDOWN: p.x = (lParam & 0x0000ffff); p.y = (lParam >> 16 ); sprintf(message,"The "frame" got a WM_RBUTTONDOWN message!nx: %iny: %in",p.x,p.y); 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,lParam); } LRESULT __stdcall SubClassProc( HWND hWnd,LPARAM lParam ) { WNDPROC wp=0; POINT p; HWND hParent=0; char message[300]; wp = (WNDPROC)GetWindowLongPtr(hWnd,GWLP_USERDATA); if (!wp) { return DefWindowProc(hWnd,lParam); } if (uMsg==WM_RBUTTONDOWN) { p.x = (lParam & 0x0000ffff); p.y = (lParam >> 16 ); sprintf(message,"Right-Click in control!nx: %iny: %innNow,we'll convert this to the coordinates of the frame and pass the message up-stream!",p.y); hParent = GetParent(hWnd); MessageBox(GetParent(hParent),MB_ICONINFORMATION); ClientToScreen(hWnd,&p); ScreenToClient(hParent,&p); SendMessage(hParent,WM_RBUTTONDOWN,MAKELPARAM(p.x,p.y)); } return CallWindowProc( wp,lParam); } 大多数本机Windows控件通过WM_COMMAND或WM_NOTIFY消息自动通知其父母.比如,在编辑控件中更改文本时.它向其父窗口发送WM_COMMAND消息 因此,您可以拦截这些消息并通过SendMessage()将它们转发到任何地方. 当您进入自定义绘图控件时,您需要了解以下内容: >什么是设备上下文. 内存设备上下文基本上是您无法进行绘图操作的地方.像bkausbk说的那样,一个缓冲区.在我编写的程序中,我需要添加一点内容,我绘制到内存设备上下文,然后在WM_PAINT事件(来自系统)中使用BitBlt()来复制所有窗口及其所有窗口的内存设备上下文孩子们已经绘制到要显示的窗口的设备上下文中. PAINTSTRUCT ps; case WM_PAINT: BeginPaint(hWnd,&ps); BitBlt(ps.hdc,cy,hMemDC,SRCCOPY); EndPaint(hWnd &ps); 无论如何,有很多东西可以学习,但我希望上面的小程序可以帮助你并给你一个模板来玩它! (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |
- 与Windows相比,Linux上的代码速度较慢
- windows – 什么是好的,免费的“虚拟机”应用程序?
- windows – 远程访问PostGIS
- 编程Windows Phone 7与正常的.NET编程不同吗?
- Windows – 域帐户使用正确的密码每隔几分钟保持锁定
- 托管和非托管DLL之间有什么区别
- Win10远程桌面 出现 身份验证错误,要求的函数不受支持,这
- 使用NetTcpBinding在WCF中进行Windows身份验证/加密
- windows-phone-7 – 无法从c#访问应用程序按钮(Windows Pho
- windows-runtime – 等同于“OnBackKeyPress”的是什么