【Windows編程】系列第十一篇:多重文件介面架構

來源:互聯網
上載者:User

標籤:

前面我們所舉的例子中都是單一文件介面架構,也就是說這個視窗裡面的客戶區就是一個文檔介面,可以編寫程式在裡面輸入或者繪製文本和圖形輸出,但是不能有出現多個文檔的情況。比如下面的UltraEdit就是一個典型的多重文件介面,他可以同時編輯多個文檔,每個文檔還可以最大化,最小化等等,我們今天就來看看多文檔的基本架構是怎麼實現的。

多重文件介面的架構建立需要幾下幾步。

  • 主架構視窗建立

主架構窗的建立跟普通的視窗沒有什麼區別,就是自己註冊一個類並用該類建立一個重疊的視窗,這個可以用CreateWindow/CreateWindowEx函數完成,主架構視窗可以用自己的菜單和狀態列。

  • 客戶區視窗建立

客戶區建立的建立同樣用你CreateWindow,但需要指定類為“MDICLIENT”,用這個類會建立多文檔的客戶區視窗。或者採用CreateWindowEx函數,指定擴充風格為WS_EX_MDICHILD。客戶區不需要菜單和狀態列。

  • 視圖視窗建立

建立工作或者視圖視窗作為實際文件視窗,這個也是需要自己註冊類並建立自己需要的視圖視窗。視圖視窗可以有自己的菜單,一般不需要狀態列。當視圖視窗啟用時,主視窗的菜單需要替換成視圖視窗的菜單,因為這個時候往往是對視圖視窗進行操作,菜單替換也是理所當然的。菜單設定通過WM_MDISETMENU訊息完成。該訊息定義如下:

SendMessage(hWndControl, WM_MDISETMENU, wParam, lParam)wParam表示新架構視窗菜單,lParam表示要設定的菜單控制代碼

OK,基本的API就這些,下面我們直接上demo程式來示範,由於視圖一般是一個多文檔的執行個體,所以demo代碼中用類來儲存視圖,每一個視圖就是一個類的執行個體:

主檔案,該檔案包括主架構視窗、客戶視窗已經視圖視窗調用:

#include <windows.h>#define CLIENT_WND_BGROUND#define IDM_FIRSTCHILD 1001#define IDM_FILE_NEW   1002HINSTANCE g_hInst;TCHAR     szMDIMainFrame[]= TEXT("MDI Main Frame");TCHAR     gszAppName[]    = TEXT("MDI Demo");HWND      ghWndMDIClient;HWND      ghWndMainFrame;HMENU     ghMainFrameMenu;void CreateChildWndMenu(void);HWND CreateDocView(HWND hParentWnd, HINSTANCE hInstance);static LRESULT CALLBACK MainFrameProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);#ifdef CLIENT_WND_BGROUNDstatic WNDPROC pfOrigClientWndProc;LRESULT CALLBACK ClientWndSubClassProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam){    switch(uMsg)    {    case WM_ERASEBKGND:        {            RECT rect;            HDC hDC = (HDC)wParam;            GetClientRect(hwnd, &rect);            HBRUSH hbr = CreateSolidBrush(RGB(125, 150, 125));            HBRUSH holdbr = (HBRUSH)SelectObject(hDC, hbr);            FillRect(hDC, &rect, hbr);            SelectObject(hDC, holdbr);            DeleteObject(hbr);        }        return TRUE;    default:        break;    }    return CallWindowProc(pfOrigClientWndProc, hwnd, uMsg, wParam, lParam); }#endifHMENU CreateMainFrameMenu(void){    //主架構菜單    HMENU hMenu = CreateMenu();    //檔案菜單    HMENU hFileMenu = CreateMenu();    AppendMenu(hFileMenu, MF_STRING, IDM_FILE_NEW, TEXT("&New"));    AppendMenu(hMenu, MF_POPUP, (UINT_PTR)hFileMenu, TEXT("&File"));    return hMenu;}int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd){    MSG msg;    WNDCLASSEX wndclass = {0};    wndclass.cbSize= sizeof(WNDCLASSEX);    wndclass.style= CS_HREDRAW | CS_VREDRAW;    wndclass.lpfnWndProc= MainFrameProc;    wndclass.hInstance= hInstance;    wndclass.hIcon= NULL;    wndclass.hCursor= LoadCursor(NULL, IDC_ARROW);    wndclass.hbrBackground= (HBRUSH)GetStockObject(WHITE_BRUSH);    wndclass.lpszClassName= szMDIMainFrame;    if(!RegisterClassEx(&wndclass))    {        MessageBox(NULL, TEXT("This program requires Windows NT!"), gszAppName, MB_ICONERROR);        return 0;    }    g_hInst = hInstance;    ghMainFrameMenu = CreateMainFrameMenu();    CreateChildWndMenu();    //Create the main MDI frame window    ghWndMainFrame = CreateWindow(szMDIMainFrame,                                 gszAppName,                                 WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN,                                CW_USEDEFAULT,// allows system choose an x position                                CW_USEDEFAULT,// allows system choose a y position                                400,                                300,                                NULL,// handle to parent window                                ghMainFrameMenu,// handle to menu                                hInstance,// handle to the instance of module                                NULL);// Long pointer to a value to be passed to the window through the     ShowWindow(ghWndMainFrame,  SW_SHOW);    UpdateWindow(ghWndMainFrame);    while(GetMessage(&msg, NULL, 0, 0))    {        TranslateMessage(&msg) ;        DispatchMessage(&msg) ;    }    return msg.wParam ;}LRESULT CALLBACK MainFrameProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam){    switch(message)    {    case WM_CREATE:        {            CLIENTCREATESTRUCT ccs;            ccs.hWindowMenu = NULL;            ccs.idFirstChild = IDM_FIRSTCHILD;            ghWndMDIClient = CreateWindow(TEXT("MDICLIENT"), NULL,                                        WS_CHILD | WS_CLIPCHILDREN | WS_VISIBLE,                                        0, 0, 0, 0, hWnd, NULL,                                        g_hInst, (void *)&ccs);#ifdef CLIENT_WND_BGROUND            pfOrigClientWndProc = (WNDPROC)SetWindowLong(ghWndMDIClient, GWL_WNDPROC, (LONG)ClientWndSubClassProc);#endif        }        return 0;    case WM_COMMAND:        switch(LOWORD(wParam))        {        case IDM_FILE_NEW:            CreateDocView(ghWndMDIClient, g_hInst);            return 0;        }        break;    case WM_DESTROY:        PostQuitMessage(0);        return 0;    }    return DefFrameProc(hWnd, ghWndMDIClient, message, wParam, lParam);}

下面是視圖視窗,每個視圖視窗由一個類來描述,本文僅僅是一個demo,只有執行個體化一個視圖視窗作為示範:

#include <windows.h>#define IDM_EDIT_COPY 1003#define IDM_EDIT_PASTE 1004class CViewInfo{public:    CViewInfo(HINSTANCE hInst);    ~CViewInfo();    HWND CreateViewWindow(HWND hParentWnd);private:    HINSTANCE m_hInst;    HWND m_hWndView;};static TCHAR szViewWndName[] = TEXT("View Window");static CViewInfo *g_pSystemInfo;static HMENU      ghChildWndMenu;extern HMENU      ghMainFrameMenu;CViewInfo::CViewInfo(HINSTANCE hInst){    m_hWndView = NULL;    m_hInst = hInst;}CViewInfo::~CViewInfo(){    m_hWndView = NULL;}LRESULT CALLBACK ViewWindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam){    switch(message)    {    case WM_MDIACTIVATE:        {            HWND hWndClient = GetParent(hWnd);            HWND hWndFrame  = GetParent(hWndClient);            HMENU hMenu = GetSubMenu(ghChildWndMenu, 0);            if (lParam == (LPARAM)hWnd)            {                SendMessage(hWndClient, WM_MDISETMENU, (WPARAM)ghChildWndMenu, (LPARAM)hMenu);                EnableMenuItem(ghChildWndMenu, IDM_EDIT_COPY, MF_GRAYED);            }            // Set the framewindow menu if losing focus            if (lParam != (LPARAM)hWnd)            {                SendMessage(hWndClient, WM_MDISETMENU, (WPARAM)ghMainFrameMenu, (LPARAM)NULL);            }            // call DrawMenuBar after the menu items are set            DrawMenuBar(hWndFrame);            return 0 ;        }    case WM_CLOSE:        delete g_pSystemInfo;        break;    case WM_DESTROY:        return 0;    }    return DefMDIChildProc(hWnd, message, wParam, lParam); //Frame window calls DefFrameProc rather than DefWindowProc}HWND CViewInfo::CreateViewWindow(HWND hParentWnd){    WNDCLASSEX wcDoc;    wcDoc.cbSize= sizeof(WNDCLASSEX);    wcDoc.style= CS_HREDRAW | CS_VREDRAW;    wcDoc.lpfnWndProc= ViewWindowProc;    wcDoc.cbClsExtra= 0;    wcDoc.cbWndExtra= 0;    wcDoc.hInstance= m_hInst;    wcDoc.hIcon= NULL;    wcDoc.hCursor= LoadCursor(NULL, IDC_ARROW);    wcDoc.hbrBackground= (HBRUSH) GetStockObject(WHITE_BRUSH);    wcDoc.lpszMenuName= NULL;    wcDoc.lpszClassName= szViewWndName;    wcDoc.hIconSm= NULL;    if(!RegisterClassEx(&wcDoc))    {        DWORD dw_LastError = GetLastError();        if(ERROR_CLASS_ALREADY_EXISTS != dw_LastError)        {            return 0;        }    }    m_hWndView = CreateWindowEx(WS_EX_MDICHILD, szViewWndName,                                 TEXT("New view"), 0, CW_USEDEFAULT,                                CW_USEDEFAULT, 300, 200,                                hParentWnd, NULL, m_hInst, NULL);    return m_hWndView;}HWND CreateDocView(HWND hParentWnd, HINSTANCE hInstance){    HWND hView;    g_pSystemInfo = new CViewInfo(hInstance);    hView = g_pSystemInfo->CreateViewWindow(hParentWnd);    if (hView == NULL)    {        delete g_pSystemInfo;        g_pSystemInfo = NULL;    }    return hView;}void CreateChildWndMenu(void){    //View菜單    ghChildWndMenu = CreateMenu();    //編輯菜單    HMENU hEditMenu = CreateMenu();    AppendMenu(hEditMenu, MF_STRING, IDM_EDIT_COPY, TEXT("&Copy"));    AppendMenu(hEditMenu, MF_STRING, IDM_EDIT_PASTE, TEXT("&Paste"));    AppendMenu(ghChildWndMenu, MF_POPUP, (UINT_PTR)hEditMenu, TEXT("&Edit"));}

本執行個體運行後,介面如下:

選擇File->New建立一個視圖後demo程式如下,可以看到菜單編程視圖的菜單:

最大化後可以看到視圖視窗和填滿客戶視窗:

雖然本程式只實現了一個視圖的執行個體,但是再增加一個是很容易的,只要想辦法在菜單中調用CreateDocView函數,並且正確處理對象指標即可。執行個體並沒有增加狀態列,因為這個對多文檔並不是必須的,要增加的讀者可以參考前面的建立Toolbar和Statusbar一文。

本執行個體實現了一個基本的多文件視窗架構,讀者朋友可以在此基礎上加上工具列、狀態列、視圖視窗建立對類的處理,多執行個體以及具體的需求,完成實用化的多重文件介面。

 

更多經驗交流可以加入Windows編程討論QQ群454398517

 

關注公眾平台:程式員互動聯盟(coder_online),你可以第一時間擷取原創技術文章,和(Java/C/C++/Android/Windows/Linux)技術大牛做朋友,線上交流編程經驗,擷取編程基礎知識,解決編程問題。程式員互動聯盟,開發人員自己的家。

轉載請註明出處http://www.coderonline.net/?p=2052,謝謝合作!

【Windows編程】系列第十一篇:多重文件介面架構

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.