Windows 如何创建Win32控件以包含其他Win32控件? 安装:几年前,我们开发了一个很好的C++交叉平台,管理了许多在Mac OS X窗口之间编写通用代码源的问题。(我们不会深入探讨这种方法的巨大缺点——我们在1993年开发了这种方法!)

Windows 如何创建Win32控件以包含其他Win32控件? 安装:几年前,我们开发了一个很好的C++交叉平台,管理了许多在Mac OS X窗口之间编写通用代码源的问题。(我们不会深入探讨这种方法的巨大缺点——我们在1993年开发了这种方法!),windows,winapi,visual-c++,Windows,Winapi,Visual C++,为了简化可重用组件的开发,我们最近添加了一个“窗格”概念来包含多个控件和用户项,基本上处理绘图和其他事件(如击键和鼠标单击)的层次性 我们成功地在MacOSX(Carbon)端构建了这种方法。然而,试图将这种方法转移到Windows(XP SP3及更高版本)已经导致了无数混乱的问题:不停地重新绘制窗口内容,事件没有传递到我们的“窗格” 在Windows上,每个窗格都转换为一个“窗口”,我怀疑这可能是问题的根源:在封闭项下重叠项可能会干扰绘图和事件传播 是否有一种公认的方法可以通过编程将控件添加到

为了简化可重用组件的开发,我们最近添加了一个“窗格”概念来包含多个控件和用户项,基本上处理绘图和其他事件(如击键和鼠标单击)的层次性

我们成功地在MacOSX(Carbon)端构建了这种方法。然而,试图将这种方法转移到Windows(XP SP3及更高版本)已经导致了无数混乱的问题:不停地重新绘制窗口内容,事件没有传递到我们的“窗格”

在Windows上,每个窗格都转换为一个“窗口”,我怀疑这可能是问题的根源:在封闭项下重叠项可能会干扰绘图和事件传播

是否有一种公认的方法可以通过编程将控件添加到分组的层次结构中?或者必须设置特定的标志才能完成此操作

(注意:尽管我们目前与XP SP3兼容,但我们不需要-我们可以将最低操作系统目标定为Windows 7。我们目前正在使用VS 2010进行开发)


斯蒂芬(Stephen)

它通常如何工作的简单分类

创建包含子窗口的父窗口(以下称为“窗格”)时,闪烁通常是由于父窗口的窗口过程处理WM_ERASEBKGND消息,并在指示子窗口重新绘制自身之前绘制其所有子窗口的“顶部”

正如Nik Bougalis所述,在创建父窗格时,如果使用CS_CLIPCHILDREN样式创建它,则DefWindowProc()执行的任何绘图都不会出现在任何窗格子窗格边界(矩形或区域)的边界内。因此,子窗口或控件占用的“屏幕空间”完全是子控件本身的责任

对于大多数标准Windows控件,这是可以的。这将解决闪烁问题

至于信息: 孩子们的每个窗口都有WM_MOUSEMOVE、WM_LBUTTONDOWN、WM_KEYDOWN(以及其他)消息。Windows将这些消息发送到具有焦点的实际窗口

如果您想让父窗口获得这些,您必须对子窗口(控件)的窗口过程进行子分类。然后在新的WndProc()中,您将有一个处理程序,用于处理要捕获并发送到父窗格的HWND的消息

下面是一个在控件中嵌入控件的简单工作示例。它显示了子分类和向上游传递消息

右键单击蓝色“窗格”中的两个子控件(编辑控件或按钮)中的任意一个


无论如何,有很多东西需要学习,但我希望上面的小程序可以帮助你,给你一个模板,让你玩它

在实施过程中可以遵循以下几点:

  • 在创建父控件(即窗格)时使用WS|U ClipSpling | WS|U CLIPCHILDREN标志
  • 在消息循环中避免WM_橡皮擦BKGND消息,并为此返回TRUE。这取决于使用符号
  • 如果有自定义绘图,请使用双缓冲绘图。-
  • 要处理子窗口消息,请使用MFC方法,即让子窗口首先处理消息。这可以通过重写windowproc来完成
    你说的是遏制,但你说的是重叠。控件是窗格的子控件吗?为窗格设置
    WS\u CLIPCHILDREN
    样式应该可以满足您的需要。如果没有,那么你需要更详细地解释你想要实现的目标。所谓“重叠”,我的意思是窗口可能包含1到(可能)10个“窗格”。窗格内可以是控件,甚至可以是其他窗格。窗格有自己的“边界”,用于“封装”我希望与它们关联的所有子项。因此,一个窗口可能有一个窗格,其大小与其父窗口的整个内容相同。通过重叠,我的意思是,根据定义,任何控件或子窗格都“在”其父窗格下。因此,单击该控件可能会变成单击父窗格,而不是子控件。您可以使用
    SS_SIMPLE
    SS_OWNERDRAW
    样式创建
    STATIC
    控件。它可以“包含”其他控件,但单击这些控件不会转到父控件,而是每个窗口本身。查看:了解详细信息。如果绘图导致闪烁,有几种技巧。请看一看可用于绘图的内存backbuffer,所有绘图都应在WM_PAINT中绘制(特别是在未使用内存DC的情况下)。
    #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:
            p.x = (lParam & 0x0000ffff);
            p.y = (lParam >> 16 );
            sprintf(message, "The \"frame\" got a WM_RBUTTONDOWN message!\nx: %i\ny: %i\n",
                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, 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) {
            p.x = (lParam & 0x0000ffff);
            p.y = (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!",
                p.x, p.y);
            hParent = GetParent(hWnd);
            MessageBox(GetParent(hParent), message, "Message", MB_ICONINFORMATION);
            ClientToScreen(hWnd, &p);
            ScreenToClient(hParent, &p);
            SendMessage(hParent, WM_RBUTTONDOWN, wParam, MAKELPARAM(p.x, p.y));
        }
        return CallWindowProc( wp, hWnd, uMsg, wParam, lParam);
    }
    
    PAINTSTRUCT ps;
    case WM_PAINT:
        BeginPaint(hWnd, &ps);
        BitBlt(ps.hdc, 0, 0, cx, cy, hMemDC, 0, 0, SRCCOPY);
        EndPaint(hWnd &ps);