zoukankan      html  css  js  c++  java
  • Windows MDI(Multiple-Document Interface)

    Windows多文档窗口编程中,需要注意的以下几点:

    1、主窗口与文档窗口之间还有一个Client Window。

    2、创建文档窗口。通常认为创建子窗口就用CreateWindow,但是MDI中创建文档窗口时,用的是发送消息的方式。具体的CreateWindow的工作由Client Window来完成。该消息是WM_MDICREATE。

    3、主菜单的变化。切换到不同的文档窗口时,主菜单会随文档窗口的类型、内容等变化。文档子窗口是通过处理WM_MDIACTIVATE消息完成的。

    4、主窗口默认的消息处理函数不是DefWindowProc,而是DefFrameProc。文档窗口和主窗口一样,默认的消息处理函数也变了,是DefMDIChildProc。它们的原型分别是

    LRESULT DefFrameProc(      
        HWND hWnd,     HWND hWndMDIClient,     UINT uMsg,     WPARAM wParam,     LPARAM lParam );
    LRESULT DefMDIChildProc(
        HWND hWnd,
        UINT uMsg,
        WPARAM wParam,
        LPARAM lParam
    );
    <<Windows Programming>>第19章源码如下:
    MDIDEMO.H
    /*-----------------------
    MDIDEMO.H header file
    -----------------------*/
    
    #define EXPORT            __declspec (dllexport)
    
    #define INIT_MENU_POS     0
    #define HELLO_MENU_POS    2
    #define RECT_MENU_POS     1
    
    #define IDM_NEWHELLO     10
    #define IDM_NEWRECT      11
    #define IDM_CLOSE        12
    #define IDM_EXIT         13
    
    #define IDM_BLACK        20
    #define IDM_RED          21
    #define IDM_GREEN        22
    #define IDM_BLUE         23
    #define IDM_WHITE        24
    
    #define IDM_TILE         30
    #define IDM_CASCADE      31
    #define IDM_ARRANGE      32
    #define IDM_CLOSEALL     33
    
    #define IDM_FIRSTCHILD  100
    View Code
    MDIDEMO.C
    /*--------------------------------------------------------
       MDIDEMO.C -- Multiple Document Interface Demonstration
                    (c) Charles Petzold, 1996
      --------------------------------------------------------*/
    
    #include <windows.h>
    #include <stdlib.h>
    #include "mdidemo.h"
    
    LRESULT CALLBACK FrameWndProc  (HWND, UINT, WPARAM, LPARAM) ;
    BOOL    CALLBACK CloseEnumProc (HWND, LPARAM) ;
    LRESULT CALLBACK HelloWndProc  (HWND, UINT, WPARAM, LPARAM) ;
    LRESULT CALLBACK RectWndProc   (HWND, UINT, WPARAM, LPARAM) ;
    
    // structure for storing data unique to each Hello child window
    typedef struct tagHELLODATA{
        UINT     iColor ;
        COLORREF clrText ;
    }HELLODATA, *LPHELLODATA ;
    
    // structure for storing data unique to each Rect child window
    typedef struct tagRECTDATA{
        short cxClient ;
        short cyClient ;
    }RECTDATA, *LPRECTDATA ;
    
    // global variables
    char      szFrameClass[] = "MdiFrame" ;
    char      szHelloClass[] = "MdiHelloChild" ;
    char      szRectClass[]  = "MdiRectChild" ;
    HINSTANCE hInst ;
    HMENU     hMenuInit, hMenuHello, hMenuRect ;
    HMENU     hMenuInitWindow, hMenuHelloWindow, hMenuRectWindow ;
    
    int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
                        PSTR szCmdLine, int iCmdShow)
    {
        HACCEL      hAccel ;
        HWND        hwndFrame, hwndClient ;
        MSG         msg ;
        WNDCLASSEX  wndclass ;
        
        hInst = hInstance ;
        
        if (!hPrevInstance) 
        {
            // Register the frame window class        
            wndclass.cbSize        = sizeof (wndclass) ;
            wndclass.style         = CS_HREDRAW | CS_VREDRAW ;
            wndclass.lpfnWndProc   = FrameWndProc ;
            wndclass.cbClsExtra    = 0 ;
            wndclass.cbWndExtra    = 0 ;
            wndclass.hInstance     = hInstance ;
            wndclass.hIcon         = LoadIcon (NULL, IDI_APPLICATION) ;
            wndclass.hCursor       = LoadCursor (NULL, IDC_ARROW) ;
            wndclass.hbrBackground = (HBRUSH) (COLOR_APPWORKSPACE + 1) ;
            wndclass.lpszMenuName  = NULL ;
            wndclass.lpszClassName = szFrameClass ;
            wndclass.hIconSm       = LoadIcon (NULL, IDI_APPLICATION) ;
            
            RegisterClassEx (&wndclass) ;
            
            // Register the Hello child window class        
            wndclass.cbSize        = sizeof (wndclass) ;
            wndclass.style         = CS_HREDRAW | CS_VREDRAW ;
            wndclass.lpfnWndProc   = HelloWndProc ;
            wndclass.cbClsExtra    = 0 ;
            wndclass.cbWndExtra    = sizeof (HANDLE) ;
            wndclass.hInstance     = hInstance ;
            wndclass.hIcon         = LoadIcon (NULL, IDI_APPLICATION) ;
            wndclass.hCursor       = LoadCursor (NULL, IDC_ARROW) ;
            wndclass.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH) ;
            wndclass.lpszMenuName  = NULL ;
            wndclass.lpszClassName = szHelloClass ;
            wndclass.hIconSm       = LoadIcon (NULL, IDI_APPLICATION) ;
            
            RegisterClassEx (&wndclass) ;
            
            // Register the Rect child window class        
            wndclass.cbSize        = sizeof (wndclass) ;
            wndclass.style         = CS_HREDRAW | CS_VREDRAW ;
            wndclass.lpfnWndProc   = RectWndProc ;
            wndclass.cbClsExtra    = 0 ;
            wndclass.cbWndExtra    = sizeof (HANDLE) ;
            wndclass.hInstance     = hInstance ;
            wndclass.hIcon         = LoadIcon (NULL, IDI_APPLICATION) ;
            wndclass.hCursor       = LoadCursor (NULL, IDC_ARROW) ;
            wndclass.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH) ;
            wndclass.lpszMenuName  = NULL ;
            wndclass.lpszClassName = szRectClass ;
            wndclass.hIconSm       = LoadIcon (NULL, IDI_APPLICATION) ;
            
            RegisterClassEx (&wndclass) ;
        }
        // Obtain handles to three possible menus & submenus    
        hMenuInit  = LoadMenu (hInst, "MdiMenuInit") ;
        hMenuHello = LoadMenu (hInst, "MdiMenuHello") ;
        hMenuRect  = LoadMenu (hInst, "MdiMenuRect") ;
        
        hMenuInitWindow  = GetSubMenu (hMenuInit,   INIT_MENU_POS) ;
        hMenuHelloWindow = GetSubMenu (hMenuHello, HELLO_MENU_POS) ;
        hMenuRectWindow  = GetSubMenu (hMenuRect,   RECT_MENU_POS) ;
        
        // Load accelerator table    
        hAccel = LoadAccelerators (hInst, "MdiAccel") ;
        
        // Create the frame window    
        hwndFrame = CreateWindow (szFrameClass, "MDI Demonstration",
            WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN,
            CW_USEDEFAULT, CW_USEDEFAULT,
            CW_USEDEFAULT, CW_USEDEFAULT,
            NULL, hMenuInit, hInstance, NULL) ;
        
        hwndClient = GetWindow (hwndFrame, GW_CHILD) ;
        
        ShowWindow (hwndFrame, iCmdShow) ;
        UpdateWindow (hwndFrame) ;
        
        // Enter the modified message loop    
        while (GetMessage (&msg, NULL, 0, 0))
        {
            if (!TranslateMDISysAccel (hwndClient, &msg) &&
                !TranslateAccelerator (hwndFrame, hAccel, &msg))
            {
                TranslateMessage (&msg) ;
                DispatchMessage (&msg) ;
            }
        }
        // Clean up by deleting unattached menus    
        DestroyMenu (hMenuHello) ;
        DestroyMenu (hMenuRect) ;
        
        return msg.wParam ;
    }
    
    LRESULT CALLBACK FrameWndProc (HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam)
    {
         static HWND         hwndClient ;
         CLIENTCREATESTRUCT  clientcreate ;
         HWND                hwndChild ;
         MDICREATESTRUCT     mdicreate ;
    
         switch (iMsg)
         {
         case WM_CREATE :          // Create the client window         
             clientcreate.hWindowMenu  = hMenuInitWindow ;
             clientcreate.idFirstChild = IDM_FIRSTCHILD ;
             hwndClient = CreateWindow ("MDICLIENT", NULL,
                 WS_CHILD | WS_CLIPCHILDREN | WS_VISIBLE,
                 0, 0, 0, 0, hwnd, (HMENU) 1, hInst,
                 (LPSTR) &clientcreate) ;
             return 0 ;
             
         case WM_COMMAND :
             switch (wParam)
             {
             case IDM_NEWHELLO :       // Create a Hello child window             
                 mdicreate.szClass = szHelloClass ;
                 mdicreate.szTitle = "Hello" ;
                 mdicreate.hOwner  = hInst ;
                 mdicreate.x       = CW_USEDEFAULT ;
                 mdicreate.y       = CW_USEDEFAULT ;
                 mdicreate.cx      = CW_USEDEFAULT ;
                 mdicreate.cy      = CW_USEDEFAULT ;
                 mdicreate.style   = 0 ;
                 mdicreate.lParam  = 0 ;
                 
                 hwndChild = (HWND) SendMessage (hwndClient,
                     WM_MDICREATE, 0,
                     (LPARAM) (LPMDICREATESTRUCT) &mdicreate) ;
                 return 0 ;
                 
             case IDM_NEWRECT :        // Create a Rect child window             
                 mdicreate.szClass = szRectClass ;
                 mdicreate.szTitle = "Rectangles" ;
                 mdicreate.hOwner  = hInst ;
                 mdicreate.x       = CW_USEDEFAULT ;
                 mdicreate.y       = CW_USEDEFAULT ;
                 mdicreate.cx      = CW_USEDEFAULT ;
                 mdicreate.cy      = CW_USEDEFAULT ;
                 mdicreate.style   = 0 ;
                 mdicreate.lParam  = 0 ;
                 
                 hwndChild = (HWND) SendMessage (hwndClient,
                     WM_MDICREATE, 0,
                     (LPARAM) (LPMDICREATESTRUCT) &mdicreate) ;
                 return 0 ;
                 
             case IDM_CLOSE :          // Close the active window             
                 hwndChild = (HWND) SendMessage (hwndClient,
                     WM_MDIGETACTIVE, 0, 0) ;
                 
                 if (SendMessage (hwndChild, WM_QUERYENDSESSION, 0, 0))
                     SendMessage (hwndClient, WM_MDIDESTROY,
                     (WPARAM) hwndChild, 0) ;
                 return 0 ;
                 
             case IDM_EXIT :           // Exit the program             
                 SendMessage (hwnd, WM_CLOSE, 0, 0) ;
                 return 0 ;
                 
                 // messages for arranging windows
             case IDM_TILE :
                 SendMessage (hwndClient, WM_MDITILE, 0, 0) ;
                 return 0 ;
                 
             case IDM_CASCADE :
                 SendMessage (hwndClient, WM_MDICASCADE, 0, 0) ;
                 return 0 ;
                 
             case IDM_ARRANGE :
                 SendMessage (hwndClient, WM_MDIICONARRANGE, 0, 0) ;
                 return 0 ;
                 
             case IDM_CLOSEALL :       // Attempt to close all children             
                 EnumChildWindows (hwndClient, &CloseEnumProc, 0) ;
                 return 0 ;
                 
             default :            // Pass to active child...             
                 hwndChild = (HWND) SendMessage (hwndClient, WM_MDIGETACTIVE, 0, 0);             
                 if (IsWindow (hwndChild))
                     SendMessage (hwndChild, WM_COMMAND, wParam, lParam) ;
                 
                 break ;        // ...and then to DefFrameProc
             }
             break ;
             
             case WM_QUERYENDSESSION :
             case WM_CLOSE :                     // Attempt to close all children             
                 SendMessage (hwnd, WM_COMMAND, IDM_CLOSEALL, 0) ;
                 
                 if (NULL != GetWindow (hwndClient, GW_CHILD))
                     return 0 ;
                 
                 break ;   // I.e., call DefFrameProc 
                 
             case WM_DESTROY :
                 PostQuitMessage (0) ;
                 return 0 ;
              }
         // Pass unprocessed messages to DefFrameProc (not DefWindowProc)
         return DefFrameProc (hwnd, hwndClient, iMsg, wParam, lParam) ;
    }
    
    BOOL CALLBACK CloseEnumProc (HWND hwnd, LPARAM lParam)
    {
        if (GetWindow (hwnd, GW_OWNER))         // Check for icon title
            return 1 ;
        
        SendMessage (GetParent (hwnd), WM_MDIRESTORE, (WPARAM) hwnd, 0) ;
        
        if (!SendMessage (hwnd, WM_QUERYENDSESSION, 0, 0))
            return 1 ;
        
        SendMessage (GetParent (hwnd), WM_MDIDESTROY, (WPARAM) hwnd, 0) ;
        return 1 ;
    }
    
    LRESULT CALLBACK HelloWndProc (HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam)
    {
        static COLORREF clrTextArray[] = { RGB (0,   0, 0),
                                           RGB (255, 0,   0),
                                           RGB (0, 255, 0), 
                                           RGB (  0, 0, 255),
                                           RGB (255, 255, 255) } ;
        static HWND     hwndClient, hwndFrame ;
        HDC             hdc ;
        HMENU           hMenu ;
        LPHELLODATA     lpHelloData ;
        PAINTSTRUCT     ps ;
        RECT            rect ;
        
        switch (iMsg)
        {
        case WM_CREATE :
            // Allocate memory for window private data        
            lpHelloData = (LPHELLODATA) HeapAlloc (GetProcessHeap (),
                HEAP_ZERO_MEMORY, 
                sizeof (HELLODATA)) ;
            lpHelloData->iColor  = IDM_BLACK ;
            lpHelloData->clrText = RGB (0, 0, 0) ;
            SetWindowLong (hwnd, 0, (long) lpHelloData) ;
            
            // Save some window handles        
            hwndClient = GetParent (hwnd) ;
            hwndFrame  = GetParent (hwndClient) ;
            return 0 ;
            
        case WM_COMMAND :
            switch (wParam)
            {
            case IDM_BLACK :
            case IDM_RED :
            case IDM_GREEN :
            case IDM_BLUE :
            case IDM_WHITE :
                // Change the text color            
                lpHelloData = (LPHELLODATA) GetWindowLong (hwnd, 0) ;
                
                hMenu = GetMenu (hwndFrame) ;
                
                CheckMenuItem (hMenu, lpHelloData->iColor,
                    MF_UNCHECKED) ;
                lpHelloData->iColor = wParam ;
                CheckMenuItem (hMenu, lpHelloData->iColor,
                    MF_CHECKED) ;
                
                lpHelloData->clrText =
                    clrTextArray[wParam - IDM_BLACK] ;
                
                InvalidateRect (hwnd, NULL, FALSE) ;
            }
            return 0 ;
            
            case WM_PAINT :
                // Paint the window            
                hdc = BeginPaint (hwnd, &ps) ;
                
                lpHelloData = (LPHELLODATA) GetWindowLong (hwnd, 0) ;
                SetTextColor (hdc, lpHelloData->clrText) ;
                
                GetClientRect (hwnd, &rect) ;
                
                DrawText (hdc, "Hello, World!", -1, &rect,
                    DT_SINGLELINE | DT_CENTER | DT_VCENTER) ;
                
                EndPaint (hwnd, &ps) ;
                return 0 ;
                
            case WM_MDIACTIVATE :            
                // Set the Hello menu if gaining focus            
                if (lParam == (LPARAM) hwnd)
                    SendMessage (hwndClient, WM_MDISETMENU,
                    (WPARAM) hMenuHello, (LPARAM) hMenuHelloWindow) ;
                
                // Check or uncheck menu item            
                lpHelloData = (LPHELLODATA) GetWindowLong (hwnd, 0) ;
                CheckMenuItem (hMenuHello, lpHelloData->iColor,
                    (lParam == (LPARAM) hwnd) ? MF_CHECKED : MF_UNCHECKED) ;
                
                // Set the Init menu if losing focus            
                if (lParam != (LPARAM) hwnd)
                    SendMessage (hwndClient, WM_MDISETMENU, (WPARAM) hMenuInit,
                    (LPARAM) hMenuInitWindow) ;
                
                DrawMenuBar (hwndFrame) ;
                return 0 ;
                
            case WM_QUERYENDSESSION :
            case WM_CLOSE :
                if (IDOK != MessageBox (hwnd, "OK to close window?", "Hello",
                    MB_ICONQUESTION | MB_OKCANCEL))
                    return 0 ;
                
                break ;   // I.e., call DefMDIChildProc
                
            case WM_DESTROY :
                lpHelloData = (LPHELLODATA) GetWindowLong (hwnd, 0) ;
                HeapFree (GetProcessHeap (), 0, lpHelloData) ;
                return 0 ;
        }
        // Pass unprocessed message to DefMDIChildProc
        return DefMDIChildProc (hwnd, iMsg, wParam, lParam) ;
    }
    
    LRESULT CALLBACK RectWndProc (HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam)
    {
        static HWND  hwndClient, hwndFrame ;
        HBRUSH       hBrush ;
        HDC          hdc ;
        LPRECTDATA   lpRectData ;
        PAINTSTRUCT  ps ;
        int          xLeft, xRight, yTop, yBottom ;
        short        nRed, nGreen, nBlue ;
        
        switch (iMsg)
        {
        case WM_CREATE :
            // Allocate memory for window private data
            
            lpRectData = (LPRECTDATA) HeapAlloc (GetProcessHeap (),
                HEAP_ZERO_MEMORY, 
                sizeof (RECTDATA)) ;
            
            SetWindowLong (hwnd, 0, (long) lpRectData) ;
            
            // Start the timer going
            
            SetTimer (hwnd, 1, 250, NULL) ;
            
            // Save some window handles
            
            hwndClient = GetParent (hwnd) ;
            hwndFrame  = GetParent (hwndClient) ;
            return 0 ;
            
        case WM_SIZE :            // If not minimized, save the window size
            
            if (wParam != SIZE_MINIMIZED)
            {
                lpRectData = (LPRECTDATA) GetWindowLong (hwnd, 0) ;
                
                lpRectData->cxClient = LOWORD (lParam) ;
                lpRectData->cyClient = HIWORD (lParam) ;
            }
            
            break ;        // WM_SIZE must be processed by DefMDIChildProc
            
        case WM_TIMER :           // Display a random rectangle
            
            lpRectData = (LPRECTDATA) GetWindowLong (hwnd, 0) ;
            
            xLeft   = rand () % lpRectData->cxClient ;
            xRight  = rand () % lpRectData->cxClient ;
            yTop    = rand () % lpRectData->cyClient ;
            yBottom = rand () % lpRectData->cyClient ;
            nRed    = rand () & 255 ;
            nGreen  = rand () & 255 ;
            nBlue   = rand () & 255 ;
            
            hdc = GetDC (hwnd) ;
            hBrush = CreateSolidBrush (RGB (nRed, nGreen, nBlue)) ;
            SelectObject (hdc, hBrush) ;
            
            Rectangle (hdc, min (xLeft, xRight), min (yTop, yBottom),
                max (xLeft, xRight), max (yTop, yBottom)) ;
            
            ReleaseDC (hwnd, hdc) ;
            DeleteObject (hBrush) ;
            return 0 ;
            
        case WM_PAINT :           // Clear the window
            
            InvalidateRect (hwnd, NULL, TRUE) ;
            hdc = BeginPaint (hwnd, &ps) ;
            EndPaint (hwnd, &ps) ;
            return 0 ;
            
        case WM_MDIACTIVATE :     // Set the appropriate menu
            if (lParam == (LPARAM) hwnd)
                SendMessage (hwndClient, WM_MDISETMENU, (WPARAM) hMenuRect,
                (LPARAM) hMenuRectWindow) ;
            else
                SendMessage (hwndClient, WM_MDISETMENU, (WPARAM) hMenuInit,
                (LPARAM) hMenuInitWindow) ;
            
            DrawMenuBar (hwndFrame) ;
            return 0 ;
            
        case WM_DESTROY :
            lpRectData = (LPRECTDATA) GetWindowLong (hwnd, 0) ;
            HeapFree (GetProcessHeap (), 0, lpRectData) ;
            KillTimer (hwnd, 1) ;
            return 0 ;
        }
        // Pass unprocessed message to DefMDIChildProc    
        return DefMDIChildProc (hwnd, iMsg, wParam, lParam) ;
    }
    View Code
    MDIDEMO.RC
    /*----------------------------
    MDIDEMO.RC resource script
    ----------------------------*/
    
    #include <windows.h>
    #include "mdidemo.h"
    
    MdiMenuInit MENU
    {
        POPUP "&File"
        {
            MENUITEM "New &Hello",             IDM_NEWHELLO
                MENUITEM "New &Rectangles",        IDM_NEWRECT
                MENUITEM SEPARATOR
                MENUITEM "E&xit",                  IDM_EXIT
        }
    }
    
    MdiMenuHello MENU
    {
        POPUP "&File"
        {
            MENUITEM "New &Hello",             IDM_NEWHELLO
                MENUITEM "New &Rectangles",        IDM_NEWRECT
                MENUITEM "&Close",                 IDM_CLOSE
                MENUITEM SEPARATOR
                MENUITEM "E&xit",                  IDM_EXIT
        }
        POPUP "&Color"
        {
            MENUITEM "&Black",                 IDM_BLACK
                MENUITEM "&Red",                   IDM_RED
                MENUITEM "&Green",                 IDM_GREEN
                MENUITEM "B&lue",                  IDM_BLUE
                MENUITEM "&White",                 IDM_WHITE
        }
        POPUP "&Window"
        {
            MENUITEM "&Cascade	Shift+F5",     IDM_CASCADE
                MENUITEM "&Tile	Shift+F4",        IDM_TILE
                MENUITEM "Arrange &Icons",         IDM_ARRANGE
                MENUITEM "Close &All",             IDM_CLOSEALL
        }
    }
    
    MdiMenuRect MENU
    {
        POPUP "&File"
        {
            MENUITEM "New &Hello",             IDM_NEWHELLO
                MENUITEM "New &Rectangles",        IDM_NEWRECT
                MENUITEM "&Close",                 IDM_CLOSE
                MENUITEM SEPARATOR
                MENUITEM "E&xit",                  IDM_EXIT
        }
        POPUP "&Window"
        {
            MENUITEM "&Cascade	Shift+F5",     IDM_CASCADE
                MENUITEM "&Tile	Shift+F4",        IDM_TILE
                MENUITEM "Arrange &Icons",         IDM_ARRANGE
                MENUITEM "Close &All",             IDM_CLOSEALL
        }
    }
    
    MdiAccel ACCELERATORS
    {
        VK_F5, IDM_CASCADE, VIRTKEY, SHIFT
            VK_F4, IDM_TILE,    VIRTKEY, SHIFT
    }
    View Code
  • 相关阅读:
    性能测试的一些大实话:会linux命令以及其它工具,到底能不能做性能分析调优?
    使用Docker方式部署Gitlab,Gitlab-Runner并使用Gitlab提供的CI/CD功能自动化构建SpringBoot项目
    Docker安装Gitlab
    Docker部署ELK
    Dockerfile中ADD命令详细解读
    使用Gitlab CI/CD功能在本地部署 Spring Boot 项目
    SSH 克隆跟HTTP 克隆地址的区别
    Docker安装Gitlab-runner
    Docker方式安装Jenkins并且插件更改国内源
    使用docker-compose部署SonarQube
  • 原文地址:https://www.cnblogs.com/licb/p/MDI.html
Copyright © 2011-2022 走看看