您的位置:首页 > 其它

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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: