windows程序设计——多重文件介面

来源:互联网 发布:米尔斯海默 知乎 编辑:程序博客网 时间:2024/06/05 21:52

简单地说,就像Windows 在一个萤幕上维护多个应用程式视窗一样,MDI 应用程式在一个显示区域内维护多个文件视窗。


框架窗口与客户窗口显示如下:


每个窗口激活时会对应各自的菜单:


frame,clientwind,childwind关系如下:


以上窗口的实现如下:

/*--------------------------------------------------------   MDIDEMO.C -- Multiple-Document Interface Demonstration                (c) Charles Petzold, 1998  --------------------------------------------------------*/#include <windows.h>#include "resource.h"//window菜单在主菜单中的index,打开的文件列表会被系统添加到这个菜单下#define INIT_MENU_POS    0#define HELLO_MENU_POS   2#define RECT_MENU_POS    1//文件列表中第一个文件对应的ID,用于wm_command中显示对应的文件窗口#define IDM_FIRSTCHILD   50000//框架回调LRESULT CALLBACK FrameWndProc  (HWND, UINT, WPARAM, LPARAM) ;//关闭所有文件窗口时的回调BOOL    CALLBACK CloseEnumProc (HWND, LPARAM) ;//hello文件窗口回调LRESULT CALLBACK HelloWndProc  (HWND, UINT, WPARAM, LPARAM) ;//画矩形窗口的回调LRESULT CALLBACK RectWndProc   (HWND, UINT, WPARAM, LPARAM) ;// structure for storing data unique to each Hello child windowtypedef struct tagHELLODATA{     UINT     iColor ;     COLORREF clrText ;}HELLODATA, * PHELLODATA ;// structure for storing data unique to each Rect child windowtypedef struct tagRECTDATA{     short cxClient ;     short cyClient ;}RECTDATA, * PRECTDATA ;// global variablesTCHAR     szAppName[]    = TEXT ("MDIDemo") ;TCHAR     szFrameClass[] = TEXT ("MdiFrame") ;TCHAR     szHelloClass[] = TEXT ("MdiHelloChild") ;TCHAR     szRectClass[]  = TEXT ("MdiRectChild") ;//应用句柄,三个菜单,并三个菜单中附带的window菜单项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 ;     WNDCLASS wndclass ;          hInst = hInstance ;          // Register the frame window class     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 ;          if (!RegisterClass (&wndclass))     {          MessageBox (NULL, TEXT ("This program requires Windows NT!"),                      szAppName, MB_ICONERROR) ;          return 0 ;     }             // Register the Hello child window class     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 ;               RegisterClass (&wndclass) ;               // Register the Rect child window class     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 ;               RegisterClass (&wndclass) ;     // Obtain handles to three possible menus & submenus     hMenuInit  = LoadMenu (hInstance, TEXT ("MdiMenuInit")) ;     hMenuHello = LoadMenu (hInstance, TEXT ("MdiMenuHello")) ;     hMenuRect  = LoadMenu (hInstance, TEXT ("MdiMenuRect")) ;     //虽然hMenuInitWindow存在,但是只有在所有文件都被关闭的时候才显示在hMenuInitWindow后个数永远为0     hMenuInitWindow  = GetSubMenu (hMenuInit,   INIT_MENU_POS) ;     hMenuHelloWindow = GetSubMenu (hMenuHello, HELLO_MENU_POS) ;     hMenuRectWindow  = GetSubMenu (hMenuRect,   RECT_MENU_POS) ;          // Load accelerator table     hAccel = LoadAccelerators (hInstance, szAppName) ;     // Create the frame window,会在这个过程里边收到wm_create消息创建client_windows     hwndFrame = CreateWindow (szFrameClass, TEXT ("MDI Demonstration"),                               WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN,                               CW_USEDEFAULT, CW_USEDEFAULT,                               CW_USEDEFAULT, CW_USEDEFAULT,                               NULL, hMenuInit, hInstance, NULL) ;     //获得在wm_create消息中创建的client_windows     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 ;}//frame处理回调LRESULT CALLBACK FrameWndProc (HWND hwnd, UINT message,                                WPARAM wParam, LPARAM lParam){     static HWND        hwndClient ;     CLIENTCREATESTRUCT clientcreate ;     HWND               hwndChild ;     MDICREATESTRUCT    mdicreate ;               switch (message)     {     case WM_CREATE:           // Create the client window          //设置hWindowMenu和idFirstChild          clientcreate.hWindowMenu  = hMenuInitWindow ;          clientcreate.idFirstChild = IDM_FIRSTCHILD ;                    hwndClient = CreateWindow (TEXT ("MDICLIENT"), NULL,                                     WS_CHILD | WS_CLIPCHILDREN | WS_VISIBLE,                                        0, 0, 0, 0, hwnd, (HMENU) 1, hInst,                                     (PSTR) &clientcreate) ;          return 0 ;               case WM_COMMAND:          switch (LOWORD (wParam))          {          case IDM_FILE_NEWHELLO:       // Create a Hello child window               //设置CLIENTCREATESTRUCT中的字段               mdicreate.szClass = szHelloClass ;               mdicreate.szTitle = TEXT ("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 ;               //给client窗口发送WM_MDICREATE消息创建HelloClass类型的子窗口               hwndChild = (HWND) SendMessage (hwndClient, WM_MDICREATE, 0,                                   (LPARAM) (LPMDICREATESTRUCT) &mdicreate) ;               return 0 ;                         case IDM_FILE_NEWRECT:        // Create a Rect child window               //设置CLIENTCREATESTRUCT中的字段               mdicreate.szClass = szRectClass ;               mdicreate.szTitle = TEXT ("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 ;               //给client窗口发送WM_MDICREATE消息创建RectClass类型的子窗口               hwndChild = (HWND) SendMessage (hwndClient, WM_MDICREATE, 0,                                   (LPARAM) (LPMDICREATESTRUCT) &mdicreate) ;               return 0 ;                         case IDM_FILE_CLOSE:          // Close the active window               //先获取当前活动窗口的句柄               hwndChild = (HWND) SendMessage (hwndClient, WM_MDIGETACTIVE, 0, 0) ;               // 先看是否能被关闭,再给client发送WM_MDIDESTROY销毁参数中指定的窗体               if (SendMessage (hwndChild, WM_QUERYENDSESSION, 0, 0))                    SendMessage (hwndClient, WM_MDIDESTROY, (WPARAM) hwndChild, 0) ;               return 0 ;                         case IDM_APP_EXIT:            // Exit the program               SendMessage (hwnd, WM_CLOSE, 0, 0) ;               return 0 ;                         // 三种排列的情况,直接由client去处理          case IDM_WINDOW_TILE:               SendMessage (hwndClient, WM_MDITILE, 0, 0) ;               return 0 ;                         case IDM_WINDOW_CASCADE:               SendMessage (hwndClient, WM_MDICASCADE, 0, 0) ;               return 0 ;                         case IDM_WINDOW_ARRANGE:               SendMessage (hwndClient, WM_MDIICONARRANGE, 0, 0) ;               return 0 ;                         case IDM_WINDOW_CLOSEALL:     // Attempt to close all children               //遍历client窗口的所有子窗口,并对每个子窗口调用CloseEnumProc(若返回值为true就继续遍历否则退出遍历)               EnumChildWindows (hwndClient, CloseEnumProc, 0) ;               return 0 ;                         default:             // 其他WM_COMMAND消息交给子窗口               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_WINDOW_CLOSEALL, 0) ;          //当client还有子窗口的时候不关闭          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, message, wParam, lParam) ;}BOOL CALLBACK CloseEnumProc (HWND hwnd, LPARAM lParam){     if (GetWindow (hwnd, GW_OWNER))         // Check for icon title          return TRUE ;     //发送WM_MDIRESTORE恢复原状     SendMessage (GetParent (hwnd), WM_MDIRESTORE, (WPARAM) hwnd, 0) ;     //询问是否能关闭     if (!SendMessage (hwnd, WM_QUERYENDSESSION, 0, 0))          return TRUE ;     //再销毁窗口     SendMessage (GetParent (hwnd), WM_MDIDESTROY, (WPARAM) hwnd, 0) ;     return TRUE ;}//hello文件窗口回调LRESULT CALLBACK HelloWndProc (HWND hwnd, UINT message,                                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 ;     PHELLODATA      pHelloData ;     PAINTSTRUCT     ps ;     RECT            rect ;          switch (message)     {     case WM_CREATE: //创建的时候在窗口的附加存储中保存一个PHELLODATA          // Allocate memory for window private data          pHelloData = (PHELLODATA) HeapAlloc (GetProcessHeap (),                              HEAP_ZERO_MEMORY, sizeof (HELLODATA)) ;          pHelloData->iColor  = IDM_COLOR_BLACK ;          pHelloData->clrText = RGB (0, 0, 0) ;          SetWindowLong (hwnd, 0, (long) pHelloData) ;                    // Save some window handles          hwndClient = GetParent (hwnd) ;          hwndFrame  = GetParent (hwndClient) ;          return 0 ;               case WM_COMMAND: //处理frame转发过来的菜单消息          switch (LOWORD (wParam))          {          case IDM_COLOR_BLACK:          case IDM_COLOR_RED:          case IDM_COLOR_GREEN:          case IDM_COLOR_BLUE:          case IDM_COLOR_WHITE:               // Change the text color               // 获得各个窗口自己的PHELLODATA数据               pHelloData = (PHELLODATA) GetWindowLong (hwnd, 0) ;               // 根据菜单项计算颜色并选中菜单,刷新窗口               hMenu = GetMenu (hwndFrame) ;               CheckMenuItem (hMenu, pHelloData->iColor, MF_UNCHECKED) ;               pHelloData->iColor = wParam ;               CheckMenuItem (hMenu, pHelloData->iColor, MF_CHECKED) ;                              pHelloData->clrText = clrTextArray[wParam - IDM_COLOR_BLACK] ;                              InvalidateRect (hwnd, NULL, FALSE) ;          }          return 0 ;               case WM_PAINT:          // Paint the window                         hdc = BeginPaint (hwnd, &ps) ;                         pHelloData = (PHELLODATA) GetWindowLong (hwnd, 0) ;          SetTextColor (hdc, pHelloData->clrText) ;                         GetClientRect (hwnd, &rect) ;                         DrawText (hdc, TEXT ("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          pHelloData = (PHELLODATA) GetWindowLong (hwnd, 0) ;          CheckMenuItem (hMenuHello, pHelloData->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, TEXT ("OK to close window?"),                                  TEXT ("Hello"),                                   MB_ICONQUESTION | MB_OKCANCEL))               return 0 ;                         break ;   // i.e., call DefMDIChildProc                    case WM_DESTROY:          pHelloData = (PHELLODATA) GetWindowLong (hwnd, 0) ;          HeapFree (GetProcessHeap (), 0, pHelloData) ;          return 0 ;     }     // Pass unprocessed message to DefMDIChildProc     return DefMDIChildProc (hwnd, message, wParam, lParam) ;}//画矩形回调LRESULT CALLBACK RectWndProc (HWND hwnd, UINT message,                               WPARAM wParam, LPARAM lParam){     static HWND hwndClient, hwndFrame ;     HBRUSH      hBrush ;     HDC         hdc ;     PRECTDATA   pRectData ;     PAINTSTRUCT ps ;     int         xLeft, xRight, yTop, yBottom ;     short       nRed, nGreen, nBlue ;          switch (message)     {     case WM_CREATE:          // Allocate memory for window private data          pRectData = (PRECTDATA) HeapAlloc (GetProcessHeap (),                                   HEAP_ZERO_MEMORY, sizeof (RECTDATA)) ;                    SetWindowLong (hwnd, 0, (long) pRectData) ;                    // 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)          {               pRectData = (PRECTDATA) GetWindowLong (hwnd, 0) ;                              pRectData->cxClient = LOWORD (lParam) ;               pRectData->cyClient = HIWORD (lParam) ;          }          break ;        // WM_SIZE must be processed by DefMDIChildProc               case WM_TIMER:            // Display a random rectangle                    pRectData = (PRECTDATA) GetWindowLong (hwnd, 0) ;                    xLeft   = rand () % pRectData->cxClient ;          xRight  = rand () % pRectData->cxClient ;          yTop    = rand () % pRectData->cyClient ;          yBottom = rand () % pRectData->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:          pRectData = (PRECTDATA) GetWindowLong (hwnd, 0) ;          HeapFree (GetProcessHeap (), 0, pRectData) ;          KillTimer (hwnd, 1) ;          return 0 ;     }          // Pass unprocessed message to DefMDIChildProc          return DefMDIChildProc (hwnd, message, wParam, lParam) ;}