ATL Windows窗体支持(1)
2011-07-14 21:33
363 查看
一.原始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
相关文章推荐
- 在Windows Mobile和Wince(Windows Embedded CE)下Win32项目加入ATL支持
- 64位windows安装memcached并使PHP支持
- windows窗体调整
- 骁龙8180移动处理器将支持Windows 10
- WLW(windows live writer) 支持的博客
- 据报道,微软正考虑支持Windows手机或Android的多系统设备
- 32位windows 支持大内存。
- Windows ATL Service 服务的创建(VS2010)
- Ansible配置支持Windows(远程节点)流程
- 让Windows 2003支持红外线通信
- 如何:禁用 Windows 窗体 DataGridView 控件的按钮列中的按钮
- [★] C# 高手 对 Windows 窗体上的控件 的认识
- iConvert Icons 图标转换生成利器,支持Windows, Mac OS X, Linux, iOS,和Android等系统
- Windows操作系统对物理内存支持
- 在windows窗体程序中单独开一个dos命令行窗口,输出我们想要的信息(调试程序常用)
- Windows平台视频录制支持视频并列模式录制
- Win32 vs. ATL Windows Programming
- Windows 窗体中的事件顺序
- 增添趣味: 给单调的 Windows 窗体应用程序增添趣味
- Windows 7/8各版本支持最大内存容量