WTL
WTL有一定的封装基础、不是mfc的框架、能够自己定制一些窗口行为
WTL对模板编程有一点要求,对UI要求高。
WTL更快的基本原理
template<class T> class Edoyun { public: void show() { T* p = static_cast<T*>(this); p->Name(); } protected: void Name() {std::cout << "Edoyun" << std::endl;} //这不是虚函数 } class Sub : public Edoyun<Sub> { public: void name() {std::cout<<"Sub"<<std::endl;} } class Sub2 : public Edoyun<Sub2> { }; int main() { Sub sub; Sub2 sub2; sub.show(); sub2.show(); }
WTL就采用了上述模板的方式来编写每个class的name,而不是采用虚函数,因为采用虚函数,子类
继承父类会导致编译占用很多空间。
ATL GUI类
ATL:Activity Template Library
ATL 窗口类
因为是基于.COM的,所以后面需要写一个CComModule,并进行初始化。
写一个窗口类MyWindow,基于模板CWindowImpl
MyWindow里DECLARE_WND_CLASS是注册名字
BEGIN_MSG_MAP和END_MSG_MAP之间注册消息和命令
#include <iostream> #include <atlbase.h> #include <atlwin.h> #include "resource.h" //定义窗口风格 typedef CWinTraits<WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN, WS_EX_APPWINDOW> EdoyunTraits; class MyWindow : public CWindowImpl<MyWindow, CWindow, EdoyunTraits> { public: //注册信息 DECLARE_WND_CLASS(_T("Edoyun Window Class")); BEGIN_MSG_MAP(MyWindow) MESSAGE_HANDLER(WM_CLOSE, OnClose) MESSAGE_HANDLER(WM_DESTROY, OnDestroy) COMMAND_ID_HANDLER(IDR_ABOUT, OnAbout) //命令菜单 END_MSG_MAP() LRESULT OnClose(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { DestroyWindow(); return 0; } LRESULT OnDestroy(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { PostQuitMessage(0); return 0; } LRESULT OnAbout(UINT wNotifyCode, WORD wParam, HWND lParam, BOOL& bHandled) { OutputDebugString(_T("OnAbout called!\r\n")); return 0; } }; //因为基于.COM,需要初始化 CComModule gModule; int main() { HRESULT hRes = gModule.Init(NULL, GetModuleHandle(NULL)); if (hRes != 0) { std::cout << hRes << std::endl; } MyWindow win; HWND hwnd = win.Create(NULL, CWindow::rcDefault, _T("edoyun atl window!")); if (hwnd == NULL) { std::cout << "create window failed\r\n"; } win.ShowWindow(SW_SHOW); win.UpdateWindow(); MSG msg; while (GetMessage(&msg, NULL, 0, 0) > 0) { TranslateMessage(&msg); DispatchMessage(&msg); } gModule.Term(); return 0; }
ATL对话框
IDD_ABOUT是添加的对话框dlg
ID_HELLO_WORLD是menu里的
#include <iostream> #include <atlbase.h> #include <atlwin.h> #include "resource.h" //定义窗口风格 typedef CWinTraits<WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN, WS_EX_APPWINDOW> EdoyunTraits; //因为基于.COM,需要初始化 CComModule gModule; class CAboutDlg : public CDialogImpl<CAboutDlg, CWindow> { public: enum {IDD = IDD_ABOUT}; BEGIN_MSG_MAP(CAboutDlg) MESSAGE_HANDLER(WM_INITDIALOG, OnInitDialog) MESSAGE_HANDLER(WM_CLOSE, OnClose) COMMAND_ID_HANDLER(IDOK, OnOK) END_MSG_MAP() LRESULT OnInitDialog(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { CenterWindow(); return true; } LRESULT OnClose(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { EndDialog(IDOK); return true; } LRESULT OnOK(WORD wNotifyCode, WORD wID, HWND hWndCtrl, BOOL& bHandled) { EndDialog(wID); return 0; } }; class MyWindow : public CWindowImpl<MyWindow, CWindow, EdoyunTraits> { public: //注册信息 DECLARE_WND_CLASS(_T("Edoyun Window Class")); BEGIN_MSG_MAP(MyWindow) MESSAGE_HANDLER(WM_CREATE, OnCreate) MESSAGE_HANDLER(WM_CLOSE, OnClose) MESSAGE_HANDLER(WM_DESTROY, OnDestroy) COMMAND_ID_HANDLER(ID_HELLO_WORLD, OnAbout) //命令菜单 END_MSG_MAP() LRESULT OnCreate(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { HMENU hMenu = LoadMenu(gModule.GetResourceInstance(), MAKEINTRESOURCE(IDR_ABOUT)); SetMenu(hMenu); return 0; } LRESULT OnClose(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { DestroyWindow(); return 0; } LRESULT OnDestroy(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { PostQuitMessage(0); return 0; } LRESULT OnAbout(UINT wNotifyCode, WORD wParam, HWND lParam, BOOL& bHandled) { OutputDebugString(_T("OnAbout called!\r\n")); CAboutDlg dlg; dlg.DoModal(); return 0; } }; int main() { HRESULT hRes = gModule.Init(NULL, GetModuleHandle(NULL)); if (hRes != 0) { std::cout << hRes << std::endl; } MyWindow win; HWND hwnd = win.Create(NULL, CWindow::rcDefault, _T("edoyun atl window!")); if (hwnd == NULL) { std::cout << "create window failed\r\n"; } win.ShowWindow(SW_SHOW); win.UpdateWindow(); MSG msg; while (GetMessage(&msg, NULL, 0, 0) > 0) { TranslateMessage(&msg); DispatchMessage(&msg); } gModule.Term(); return 0; }
装修模式
先定义装修模块,这个装修模块有两个参数,第一个是class,第二个是COLORREF。class就表示要装修的类,填入这个类,这个类就会去把背景颜色换成COLORREF。第二个COLORREF是我们要换的颜色,也可以是图片。这个模块可以用到dlg上,也可以用到其他的按钮上、控件上。
template<class T, COLORREF clr> class CPaintBackground :public CMessageMap { public: CPaintBackground() { m_br = CreateSolidBrush(clr); } ~CPaintBackground() { if (m_br != NULL) { DeleteObject(m_br); m_br = NULL; } } BEGIN_MSG_MAP(CPaintBackground) MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBkgnd) END_MSG_MAP() LRESULT OnEraseBkgnd(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { T* p = static_cast<T*>(this); HDC dc = (HDC)wParam; RECT rc; p->GetClientRect(&rc); FillRect(dc, &rc, m_br); return true; } private: HBRUSH m_br; };
采用多继承的方式,让我们要装修的类去继承这个模块,同时把COLORREF填好。
typedef CPaintBackground<MyWindow, BACKGNDCLR> CPaintBkgndBase;
使用CHAIN_MSG_MAP,填入CPaintBkgndBase。将消息导入到其他类里面去处理,就是将消息导入到CPaintBkgndBase中去处理
#define BACKGNDCLR RGB(0, 255, 0) class MyWindow : public CWindowImpl<MyWindow, CWindow, EdoyunTraits>, public CPaintBackground<MyWindow, BACKGNDCLR> { public: //注册信息 DECLARE_WND_CLASS(_T("Edoyun Window Class")); typedef CPaintBackground<MyWindow, BACKGNDCLR> CPaintBkgndBase; BEGIN_MSG_MAP(MyWindow) MESSAGE_HANDLER(WM_CREATE, OnCreate) MESSAGE_HANDLER(WM_CLOSE, OnClose) MESSAGE_HANDLER(WM_DESTROY, OnDestroy) COMMAND_ID_HANDLER(ID_HELLO_WORLD, OnAbout) //命令菜单 CHAIN_MSG_MAP(CPaintBkgndBase) //将消息导入到其他类里面去处理 END_MSG_MAP() LRESULT OnCreate(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { HMENU hMenu = LoadMenu(gModule.GetResourceInstance(), MAKEINTRESOURCE(IDR_ABOUT)); SetMenu(hMenu); return 0; } LRESULT OnClose(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { DestroyWindow(); return 0; } LRESULT OnDestroy(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { PostQuitMessage(0); return 0; } LRESULT OnAbout(UINT wNotifyCode, WORD wParam, HWND lParam, BOOL& bHandled) { OutputDebugString(_T("OnAbout called!\r\n")); CAboutDlg dlg; dlg.DoModal(); return 0; } };