zoukankan      html  css  js  c++  java
  • ATL Windows窗体支持(1)

         一.原始Win32窗体

    #include "stdafx.h" // Includes windows.h and tchar.h
    LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
    // Entry point
    int APIENTRY _tWinMain(HINSTANCE hinst,
        HINSTANCE /*hinstPrev*/,
        LPTSTR    pszCmdLine,
        int       nCmdShow) {
            // Register the main window class
            LPCTSTR     pszMainWndClass = __T("WindowsApp");
            WNDCLASSEX  wc = { sizeof(WNDCLASSEX) };
            wc.style         = CS_HREDRAW | CS_VREDRAW;
            wc.hInstance     = hinst;
            wc.hIcon         = LoadIcon(0, IDI_APPLICATION);
            wc.hCursor       = LoadCursor(0, IDC_ARROW);
            wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
            wc.lpszClassName = pszMainWndClass;
            wc.lpfnWndProc   = WndProc;
            if( !RegisterClassEx(&wc) ) return -1;
    
            // Create the main window
            HWND    hwnd = CreateWindowEx(WS_EX_CLIENTEDGE,
                pszMainWndClass,
                __T("Windows Application"),
                WS_OVERLAPPEDWINDOW,
                CW_USEDEFAULT, 0,
                CW_USEDEFAULT, 0,
                0, 0, hinst, 0);
            if( !hwnd ) return -1;
    
            // Show the main window
            ShowWindow(hwnd, nCmdShow);
            UpdateWindow(hwnd);
    
            // Main message loop
            MSG msg;
            while( GetMessage(&msg, 0, 0, 0) ) {
                TranslateMessage(&msg);
                DispatchMessage(&msg);
            }
    
            return msg.wParam;
    }
    
    // Windows procedure
    LRESULT CALLBACK WndProc(HWND hwnd, UINT nMsg, WPARAM wparam,
        LPARAM lparam) {
            switch( nMsg ) {
                // Message handlers for messages we're interested in
            case WM_PAINT: {
                PAINTSTRUCT ps;
                HDC         hdc = BeginPaint(hwnd, &ps);
                RECT        rect; GetClientRect(hwnd, &rect);
                DrawText(hdc, __T("Hello, Windows"), -1, &rect,
                    DT_CENTER | DT_VCENTER | DT_SINGLELINE);
                EndPaint(hwnd, &ps);
                           }
                           break;
    
                           // Post the quit message when main window is destroyed
            case WM_DESTROY:
                PostQuitMessage(0);
                break;
    
                // Let Windows handle messages we don't want
            default:
                return DefWindowProc(hwnd, nMsg, wparam, lparam);
                break;
            }
    
            return 0;
    }
    
    
    

    二.CWindow

    首先封装这一部分代码

    // Create the main window
    HWND    hwnd = CreateWindowEx(WS_EX_CLIENTEDGE,
        pszMainWndClass,
        __T("Windows Application"),
        WS_OVERLAPPEDWINDOW,
        CW_USEDEFAULT, 0,
        CW_USEDEFAULT, 0,
        0, 0, hinst, 0);
    if( !hwnd ) return -1;
    
    // Show the main window
    ShowWindow(hwnd, nCmdShow);
    UpdateWindow(hwnd);
    

    用CWindow替换此部分代码

    CWindow wnd;
    wnd.Create(pszMainWndClass, 0, CWindow::rcDefault,
        __T("Windows Application"), WS_OVERLAPPEDWINDOW,
        WS_EX_CLIENTEDGE );
    
    if (!wnd) {
        return FALSE;
    }
    
    wnd.CenterWindow( );
    wnd.ShowWindow( nCmdShow );
    wnd.UpdateWindow( );
    

    即将操作封装在一个类中,其他不变

    这里似乎看不到有多少的便利性,CWindow还提供了一些常用操作Windows的方法,内部存有一个HWND句柄

    三.CWindowImpl

    3.1迁移消息循环

    class CMainWindow : public CWindowImpl<CMainWindow> {
        BEGIN_MSG_MAP( CMainWindow )
            MESSAGE_HANDLER( WM_PAINT, OnPaint )
            MESSAGE_HANDLER( WM_DESTROY, OnDestroy )
        END_MSG_MAP()
    
        LRESULT OnPaint( UINT, WPARAM, LPARAM, BOOL& ){
            
            PAINTSTRUCT ps;
            HDC         hdc = BeginPaint(&ps);
            RECT        rect; GetClientRect(&rect);
            DrawText(hdc, __T("Hello, Windows"), -1, &rect,
                DT_CENTER | DT_VCENTER | DT_SINGLELINE);
            EndPaint(&ps);
            return 0;
        }
    
        LRESULT OnDestroy( UINT, WPARAM, LPARAM, BOOL& ){
            PostQuitMessage( 0 );
            return 0;
        }
    };
    
    LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
    // Entry point
    int APIENTRY _tWinMain(HINSTANCE hinst,
        HINSTANCE /*hinstPrev*/,
        LPTSTR    pszCmdLine,
        int       nCmdShow) {
    
            CMainWindow wnd;
            wnd.Create(NULL, CMainWindow::rcDefault,
                __T("Windows Application"),  WS_OVERLAPPEDWINDOW|WS_VISIBLE);
    
            // Main message loop
            MSG msg;
            while( GetMessage(&msg, 0, 0, 0) ) {
                TranslateMessage(&msg);
                DispatchMessage(&msg);
            }
    
            return msg.wParam;
    }
    

    现在的代码明显简化

    CWindowImpl的消息循环类似MFC,BEGIN_MSG_MAP,MESSAGE_HANDLER,END_MSG_MAP

    展开后代码类似如下

    // BEGIN_MSG_MAP(CMainWindow)
    BOOL ProcessWindowMessage(HWND hWnd, UINT uMsg, WPARAM wParam,
        LPARAM lParam, LRESULT& lResult,
        DWORD dwMsgMapID = 0) {
            BOOL bHandled = TRUE;
            switch (dwMsgMapID) {
            case 0:
    
                // MESSAGE_HANDLER(WM_PAINT, OnPaint)
                if(uMsg == WM_PAINT) {
                    bHandled = TRUE;
                    lResult = OnPaint(uMsg, wParam, lParam, bHandled);
                    if (bHandled) return TRUE;
                }
    
                // END_MSG_MAP()
                break;
            default:
                ATLTRACE2(atlTraceWindowing, 0,
                    _T("Invalid message map ID (%i)\n"),
                    dwMsgMapID);
                ATLASSERT(FALSE);
                break;
            }
            return FALSE;
    }
    
    
    

    3.2命令处理

    如下COMMAND_HANDLER,即WM_COMMAND 的处理

    class CMainWindow : public CWindowImpl<CMainWindow> {
    public:
        BEGIN_MSG_MAP(CMainWindow)
            MESSAGE_HANDLER(WM_PAINT, OnPaint)
            COMMAND_HANDLER(ID_FILE_EXIT, 0, OnFileExit)
            COMMAND_HANDLER(ID_HELP_ABOUT, 0, OnHelpAbout)
        END_MSG_MAP()
        ...
            LRESULT OnFileExit(WORD wNotifyCode, WORD wID, HWND hWndCtl,
            BOOL& bHandled);
        LRESULT OnHelpAbout(WORD wNotifyCode, WORD wID, HWND hWndCtl,
            BOOL& bHandled);
    };
    

    3.3消息链

    在窗体继承关系时,需要使用消息链才可以使子类使用父级消息,用CHAIN_MSG_MAP指向父类

    template <typename Deriving>
    class CFileHandler {
    public:
        // Message map in base class
        BEGIN_MSG_MAP(CMainWindow)
            COMMAND_ID_HANDLER(ID_FILE_NEW, OnFileNew)
            COMMAND_ID_HANDLER(ID_FILE_OPEN, OnFileOpen)
            COMMAND_ID_HANDLER(ID_FILE_SAVE, OnFileSave)
            COMMAND_ID_HANDLER(ID_FILE_SAVE_AS, OnFileSaveAs)
            COMMAND_ID_HANDLER(ID_FILE_EXIT, OnFileExit)
        END_MSG_MAP()
    
        LRESULT OnFileNew(WORD, WORD, HWND, BOOL&);
        LRESULT OnFileOpen(WORD, WORD, HWND, BOOL&);
        LRESULT OnFileSave(WORD, WORD, HWND, BOOL&);
        LRESULT OnFileSaveAs(WORD, WORD, HWND, BOOL&);
        LRESULT OnFileExit(WORD, WORD, HWND, BOOL&);
    };
    
    class CMainWindow :
        public CWindowImpl<CMainWindow, CWindow, CMainWinTraits>,
        public CFileHandler<CMainWindow>
    {
    public:
        BEGIN_MSG_MAP(CMainWindow)
            MESSAGE_HANDLER(WM_PAINT, OnPaint)
            COMMAND_ID_HANDLER(ID_HELP_ABOUT, OnHelpAbout)
            // Chain to a base class
            CHAIN_MSG_MAP(CFileHandler<CMainWindow>)
        END_MSG_MAP()
        ...
    };
    
    

    3.4分段消息链

    即不想全部消息继承,可以选段CHAIN_MSG_MAP_ALT

    // in class CBase:
    BEGIN_MSG_MAP( CBase )
        MESSAGE_HANDLER( WM_CREATE, OnCreate1 )
        MESSAGE_HANDLER( WM_PAINT, OnPaint1 )
        ALT_MSG_MAP( 100 )
        MESSAGE_HANDLER( WM_CREATE, OnCreate2 )
        MESSAGE_HANDLER( WM_PAINT, OnPaint2 )
        ALT_MSG_MAP( 101)
        MESSAGE_HANDLER( WM_CREATE, OnCreate3 )
        MESSAGE_HANDLER( WM_PAINT, OnPaint3 )
    END_MSG_MAP()
    
    class CDerived: public CBase {
        BEGIN_MSG_MAP( CDerived )
            CHAIN_MSG_MAP_ALT( CBase, 100 )
        END_MSG_MAP()
        ...
    

    100,将会执行OnCreate2 和OnPaint2

    3.5窗体样式

    typedef CWinTraits<WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN
        |WS_CLIPSIBLINGS, 0> CControlWinTraits;
    class CMainWindow : public CWindowImpl<CMainWindow,CWindow,CControlWinTraits> {
    

    CControlWinTraits是默认的窗体样式,当不指定样式时,则用默认的样式

    CMainWindow wnd;
    wnd.Create(NULL, CMainWindow::rcDefault,
        __T("Windows Application"),  WS_OVERLAPPEDWINDOW|WS_VISIBLE);
    

    也可以自定义CWinTraits,有2种方式
    (1)

    typedef                                             
        CWinTraits<WS_OVERLAPPEDWINDOW|WS_VISIBLE,                                  
        0>                                   
        CChildWinTraits; 
    class CMainWindow : public CWindowImpl<CMainWindow,CWindow,CChildWinTraits> {
    

    (2)

    class CMainWindow : public CWindowImpl<CMainWindow,CWindow,CWinTraits<WS_OVERLAPPEDWINDOW|WS_VISIBLE,0>> {
    

    这样在创建窗体,可以不指定窗体样式参数

    3.6修改窗体类名

    DECLARE_WND_CLASS("my window class");
    

    或者

    DECLARE_WND_CLASS_EX(
    "my window class",       // class name
        CS_HREDRAW|CS_VREDRAW,   // class style
        COLOR_WINDOW             // background color
        );
    

    参数越多则越灵活

    #define DECLARE_WND_CLASS(WndClassName) \
    static ATL::CWndClassInfo& GetWndClassInfo() \
    { \
        static ATL::CWndClassInfo wc = \
        { \
            { sizeof(WNDCLASSEX), CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS, StartWindowProc, \
              0, 0, NULL, NULL, NULL, (HBRUSH)(COLOR_WINDOW + 1), NULL, WndClassName, NULL }, \
            NULL, NULL, IDC_ARROW, TRUE, 0, _T("") \
        }; \
        return wc; \
    }
    
    #define DECLARE_WND_CLASS_EX(WndClassName, style, bkgnd) \
    static ATL::CWndClassInfo& GetWndClassInfo() \
    { \
        static ATL::CWndClassInfo wc = \
        { \
            { sizeof(WNDCLASSEX), style, StartWindowProc, \
              0, 0, NULL, NULL, NULL, (HBRUSH)(bkgnd + 1), NULL, WndClassName, NULL }, \
            NULL, NULL, IDC_ARROW, TRUE, 0, _T("") \
        }; \
        return wc; \
    }
    

    也可以直接通过获取GetWndClassInfo方法来直接修改,这样最灵活,值得注意的是光标是特殊处理

    CMainWindow( ) {
        CWndClassInfo& wci = GetWndClassInfo();
    
        if( !wci.m_atom ) {
            wci.m_wc.lpszMenuName = MAKEINTRESOURCE(IDC_ATLHELLOWIN);
            wci.m_wc.hIcon = LoadIcon(
                _AtlBaseModule.GetResourceInstance(),
                MAKEINTRESOURCE(IDI_ATLHELLOWIN));
            wci.m_wc.hIconSm = LoadIcon(
                _AtlBaseModule.GetResourceInstance(),
                MAKEINTRESOURCE(IDI_SMALL));
            wci.m_wc.hbrBackground = CreateHatchBrush(HS_DIAGCROSS,
                RGB(0, 0, 255));
        }
    }
    

    3.7窗体超类化

    就是扩展内置控件功能,只不过继承的不是Button,CheckBox而是CWindowImpl,使用DECLARE_WND_SUPERCLASS宏来标记,若指定Edit,则呈现的将是一个TextBox

    DECLARE_WND_SUPERCLASS( _T("BeepButton"), _T("Edit") )
    

    指定Button则显示一个按钮

    class CBeepButton: public CWindowImpl< CBeepButton >
    {
    public:
        DECLARE_WND_SUPERCLASS( _T("BeepButton"), _T("Button") )
        BEGIN_MSG_MAP( CBeepButton )
            MESSAGE_HANDLER( WM_LBUTTONDOWN, OnLButtonDown )
        END_MSG_MAP()
    
        LRESULT OnLButtonDown( UINT, WPARAM, LPARAM, BOOL& bHandled )
        {
            MessageBeep( MB_ICONASTERISK );
            bHandled = FALSE; // alternatively: DefWindowProc()
            return 0;
        }
    }; // CBeepButton
    
    const int ID_BUTTON1 = 101;
    const int ID_BUTTON2 = 102;
    
    class CMyWindow: public CWindowImpl< CMyWindow, CWindow,
        CWinTraits<WS_OVERLAPPEDWINDOW|WS_VISIBLE> >
    {
        CBeepButton b1, b2;
    
        BEGIN_MSG_MAP( CMyWindow )
            MESSAGE_HANDLER( WM_CREATE, OnCreate )
            COMMAND_CODE_HANDLER( BN_CLICKED, OnClick )
        END_MSG_MAP()
    
        LRESULT OnClick(WORD wNotifyCode, WORD wID, HWND hWndCtl,
            BOOL& bHandled)
        {
            ATLTRACE( "Control %d clicked\n", wID );
            return 0;
        }
    
        LRESULT OnCreate( UINT, WPARAM, LPARAM, BOOL& )
        {
            RECT r1 = { 10, 10, 250, 80 };
            b1.Create(*this, r1, __T("beep1"), WS_CHILD|WS_VISIBLE, 0, ID_BUTTON1);
            RECT r2 = { 10, 110, 250, 180 };
            b2.Create(*this, r2, __T("beep2"), WS_CHILD|WS_VISIBLE, 0, ID_BUTTON2);
            return 0;
        }
    }; // CMyWindow
    // Entry point
    int APIENTRY _tWinMain(HINSTANCE hinst,
        HINSTANCE /*hinstPrev*/,
        LPTSTR    pszCmdLine,
        int       nCmdShow) {
    
            CMyWindow wnd;
            wnd.Create(NULL, CMyWindow::rcDefault,
                __T("Windows Application"));
    
            // Main message loop
            MSG msg;
            while( GetMessage(&msg, 0, 0, 0) ) {
                TranslateMessage(&msg);
                DispatchMessage(&msg);
            }
    
            return msg.wParam;
    }
    

    3.8窗体子类化

    这种方式更灵活,更易扩展控件行为

    class CNoNumEdit: public CWindowImpl< CNoNumEdit >
    {
        BEGIN_MSG_MAP( CNoNumEdit )
            MESSAGE_HANDLER( WM_CHAR, OnChar )
        END_MSG_MAP()
    
        LRESULT OnChar( UINT, WPARAM wParam, LPARAM, BOOL& bHandled )
        {
            TCHAR ch = wParam;
            if( _T(''0'') <= ch && ch <= _T(''9'') )
                MessageBeep( 0 );
            else
                bHandled = FALSE;
            return 0;
        }
    };
    
    const int ID_BUTTON1 = 101;
    
    class CMyWindow: public CWindowImpl< CMyWindow, CWindow,
        CWinTraits<WS_OVERLAPPEDWINDOW|WS_VISIBLE> >
    {
        CNoNumEdit ed;
    
        BEGIN_MSG_MAP( CMyWindow )
            MESSAGE_HANDLER( WM_CREATE, OnCreate )
        END_MSG_MAP()
    
        LRESULT OnCreate( UINT, WPARAM, LPARAM, BOOL& )
        {
            ed.SubclassWindow( GetDlgItem( ID_BUTTON1 ) );
    
            return 0;
        }
    };
    

    这个类东西太多,写点是点

    参考:http://www.vckbase.com/document/viewdoc/?id=1119

  • 相关阅读:
    97. Interleaving String
    96. Unique Binary Search Trees
    95. Unique Binary Search Trees II
    94. Binary Tree Inorder Traversal
    odoo many2many字段 指定打开的form视图
    docker sentry 配置文件位置
    postgres 计算时差
    postgres 字符操作补位,字符切割
    postgres判断字符串是否为时间,数字
    odoo fields_view_get
  • 原文地址:https://www.cnblogs.com/Clingingboy/p/2106795.html
Copyright © 2011-2022 走看看