• 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

  • 相关阅读:
    selenium之css选择器高级用法
    常系数线性齐次递推新理解
    关于莫队本质的理解
    2021.5.8总结
    决策单调性优化dp
    字符串 复习
    5.1总结
    树分块 学习笔记
    莫反 复习
    P4570 [BJWC2011]元素
  • 原文地址:https://www.cnblogs.com/Clingingboy/p/2106795.html
Copyright © 2020-2023  润新知