一. 基础控件
除了CWindowImpl和CDialogImpl 这种窗口外,其他的界面窗口可统称为控件。WTL提供了大量的基础窗口控件,主要在atlctrls.h中定义,它们都继承自CWindow类:
二. 对话框程序
WTL中的消息机制比MFC中的要灵活的多,下面通过一个简单的对话框程序,对子类化,消息反射,重绘以及双缓冲技术的使用进行说明。如果有WTL工程向导的话,可以直接使用向导创建模式对话框程序,如果没有的话,则可以根据以下步骤手动创建一个对话框工程:
1. 资源创建
需要两个Dialog资源,一个作为主窗口,一个作为弹窗:
2. 代码
三个文件:stdafx.h 公共引用;MainDlg.h 对话框定义及实现;main.cpp 程序入口
//stdafx.h
#pragma once
// Change these values to use different versions
#define WINVER 0x0601
#define _WIN32_WINNT 0x0601
#define _WIN32_IE 0x0700
#define _RICHEDIT_VER 0x0500
#include <atlbase.h>
#include <atlapp.h>
extern CAppModule _Module;
#include <atlwin.h>
#if defined _M_IX86
#pragma comment(linker, "/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='x86' publicKeyToken='6595b64144ccf1df' language='*'\"")
#elif defined _M_IA64
#pragma comment(linker, "/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='ia64' publicKeyToken='6595b64144ccf1df' language='*'\"")
#elif defined _M_X64
#pragma comment(linker, "/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='amd64' publicKeyToken='6595b64144ccf1df' language='*'\"")
#else
#pragma comment(linker, "/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"")
#endif
// MainDlg.h
#pragma once
#include <atlbase.h>
#include <atlwinx.h>
#include <atlcrack.h>
#include <atlctrls.h>
#include <atlframe.h>
#include "resource.h"
class CODButtonImpl : public CWindowImpl<CODButtonImpl, CButton>,
public COwnerDraw<CODButtonImpl>
{
public:
BEGIN_MSG_MAP_EX(CODButtonImpl)
REFLECTED_COMMAND_HANDLER_EX(IDC_CUSTOM_BUTTON, BN_DOUBLECLICKED, OnClicked)
MESSAGE_HANDLER(WM_SETCURSOR, OnSetCursor)
CHAIN_MSG_MAP_ALT(COwnerDraw<CODButtonImpl>, 1)
DEFAULT_REFLECTION_HANDLER()
END_MSG_MAP()
CODButtonImpl()
{
m_bmp;
}
LRESULT OnSetCursor(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
bHandled = TRUE;//will decide the return value of CODButtonImpl::ProcessWindowMessage
static HCURSOR hcur = LoadCursor(NULL, IDC_HAND);
if (NULL != hcur)
{
SetCursor(hcur);
return TRUE;//will decide the value of CODButtonImpl::ProcessWindowMessage's param: lResult
}
else
{
SetMsgHandled(false);
return FALSE;
}
}
void DrawItem(LPDRAWITEMSTRUCT lpdis)// must be implemented, required by COwnerDraw.
{
//SetMsgHandled(FALSE);// if you don't how to process this msg, then set handled flag as FALSE to spread it to other work flow.
//return;
CDCHandle dc = lpdis->hDC;
CDC dcMem;
dcMem.CreateCompatibleDC(dc);
dc.SaveDC();
dcMem.SaveDC();
// Draw the button's background, red if it has the focus, blue if not.
if (lpdis->itemState & ODS_FOCUS)
dc.FillSolidRect(&lpdis->rcItem, RGB(255, 0, 0));
else
dc.FillSolidRect(&lpdis->rcItem, RGB(0, 0, 255));
// Draw the bitmap in the top-left, or offset by 1 pixel if the button
// is clicked.
//dcMem.SelectBitmap(m_bmp);
if (lpdis->itemState & ODS_SELECTED)
dc.BitBlt(1, 1, 80, 80, dcMem, 0, 0, SRCCOPY);
else
dc.BitBlt(0, 0, 80, 80, dcMem, 0, 0, SRCCOPY);
dcMem.RestoreDC(-1);
dc.RestoreDC(-1);
}
void OnClicked(WORD wNotifyCode, WORD wID, HWND hWndCtl)
{
//assert(wNotifyCode == BN_DOUBLECLICKED && wID == IDC_CUSTOM_BUTTON && hWndCtl == m_hWnd)
return;
}
private:
HBITMAP m_bmp;
};
class COwerTree :public CWindowImpl<COwerTree, CTreeViewCtrl>,
public CCustomDraw<COwerTree>
{
BEGIN_MSG_MAP(COwerTree)
REFLECTED_NOTIFY_CODE_HANDLER_EX(TVN_ITEMEXPANDING, OnItemExpanding)
CHAIN_MSG_MAP_ALT(CCustomDraw<COwerTree>, 1)
DEFAULT_REFLECTION_HANDLER()
END_MSG_MAP()
LRESULT OnItemExpanding(NMHDR* phdr)
{
//SetMsgHandled(FALSE);
//return FALSE;
NMTREEVIEW* pnmtv = (NMTREEVIEW*)phdr;
if (pnmtv->action & TVE_COLLAPSE)
return TRUE;
else
return FALSE;
}
DWORD OnPrePaint(int idCtrl, LPNMCUSTOMDRAW lpNMCD)
{
OCM_NOTIFY - OCM__BASE;
return CDRF_NOTIFYITEMDRAW;
}
DWORD OnItemPrePaint(int idCtrl, LPNMCUSTOMDRAW lpNMCD)
{
NMTVCUSTOMDRAW* pnmtv = (NMTVCUSTOMDRAW*)lpNMCD;
RECT rcItem = lpNMCD->rc;
HDC hdcItem = lpNMCD->hdc;
POINT ptItem;
ptItem.x = rcItem.left + 1;
ptItem.y = rcItem.top + 1;
UINT uFlags;
HTREEITEM hItem = HitTest(ptItem, &uFlags);
if (!hItem) return CDRF_DODEFAULT;
return CDRF_SKIPDEFAULT;
}
};
class CMainDlg : public CDialogImpl<CMainDlg>, public CDoubleBufferImpl<CMainDlg>
{
public:
enum { IDD = IDD_MAINDLG }; //WM_PAINT
BEGIN_MSG_MAP(CMainDlg)
MESSAGE_HANDLER(WM_CLOSE, OnClose)
MESSAGE_HANDLER(WM_DESTROY, OnDestroy)
MESSAGE_HANDLER(WM_INITDIALOG, OnInitDialog)
COMMAND_ID_HANDLER(IDC_ABOUT, OnAppAbout)
COMMAND_ID_HANDLER(IDOK, OnOK)
COMMAND_ID_HANDLER(IDCANCEL, OnCancel)
CHAIN_MSG_MAP(CDoubleBufferImpl<CMainDlg>)// responsible for handling WM_PAINT msg.
REFLECT_NOTIFICATIONS()// send msg to child ctrl according to the hwnd parsed from wParam or lParam.
ALT_MSG_MAP(1)
MESSAGE_HANDLER(WM_SETCURSOR, OnSetCursor_OK)
ALT_MSG_MAP(2)
MESSAGE_HANDLER(WM_SETCURSOR, OnSetCursor_Exit)
END_MSG_MAP()
// Handler prototypes (uncomment arguments if needed):
// LRESULT MessageHandler(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
// LRESULT CommandHandler(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
// LRESULT NotifyHandler(int /*idCtrl*/, LPNMHDR /*pnmh*/, BOOL& /*bHandled*/)
CMainDlg() :m_wndOKBtn(this, 1), m_wndExitBtn(this, 2) {}
LRESULT OnInitDialog(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
{
// center the dialog on the screen
CenterWindow();
m_wndOKBtn.SubclassWindow(GetDlgItem(IDOK));//subclass the button, which will change the winproc, unlike the attach method which won't change the winproc.
m_wndExitBtn.SubclassWindow(GetDlgItem(IDCANCEL));//handle won't be destoryed when deconstruct, but once the handle is destoryed, unsubclass will be conducted automatically.
m_ownBtn.SubclassWindow(GetDlgItem(IDC_CUSTOM_BUTTON));
m_ownTree.SubclassWindow(GetDlgItem(IDC_TREE1));
bHandled = TRUE;//will affect the return value of CMainDlg::ProcessWindowMessage, which is called in Winproc, so you can look up the Winproc to know about the behavior.
return TRUE;//will affect the value of CMainDlg::ProcessWindowMessage's output param: lResult.
}
LRESULT OnClose(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
//DestroyWindow();
m_nExitCode = 0;
::DestroyWindow(m_hWnd);
bHandled = TRUE;
return TRUE;
}
LRESULT OnDestroy(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
{
PostQuitMessage(m_nExitCode);
return 0;
}
LRESULT OnAppAbout(WORD wNotifyCode, WORD wID, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
{
if (wNotifyCode == BN_DOUBLECLICKED && wID == IDC_ABOUT)// you need change the button's Notify attribute value to True to make it support double click.
{
CSimpleDialog<IDD_ABOUTBOX, FALSE> dlg;
dlg.DoModal();
}
else if (wNotifyCode == BN_CLICKED && wID == IDC_ABOUT)
{
}
return 0;
}
LRESULT OnOK(WORD /*wNotifyCode*/, WORD wID, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
{
// TODO: Add validation code
//EndDialog(wID);
m_nExitCode = wID;
::DestroyWindow(m_hWnd);
return 0;
}
LRESULT OnCancel(WORD /*wNotifyCode*/, WORD wID, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
{
//EndDialog(wID);
m_nExitCode = wID;
::DestroyWindow(m_hWnd);
return 0;
}
LRESULT OnSetCursor_OK(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
bHandled = TRUE;//will decide the return value of CContainedWindow::ProcessWindowMessage
static HCURSOR hcur = LoadCursor(NULL, IDC_HAND);
if (NULL != hcur)
{
SetCursor(hcur);
return TRUE;//will decide the value of CContainedWindow::ProcessWindowMessage's param: lResult
}
else
{
SetMsgHandled(false);
return FALSE;
}
}
LRESULT OnSetCursor_Exit(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) {
static HCURSOR hcur = LoadCursor(NULL, IDC_NO);
bHandled = TRUE;
if (NULL != hcur)
{
SetCursor(hcur);
return TRUE;
}
else
{
SetMsgHandled(false);
return FALSE;
}
}
void DoPaint(CDCHandle memdc)// Forcedly required by CDoubleBufferImpl, you can draw on memdc in this method
{
RECT rc;
GetClientRect(&rc);
memdc.FillSolidRect(&rc, RGB(255, 255, 255));// draw background.
//memdc.TextOutW(10, 10, _T("double buffer test"));//draw text.
//memdc.Ellipse(50, 50, 200, 200);//draw geometries.
return;
}
protected:
int m_nExitCode = 0;
CContainedWindow m_wndOKBtn, m_wndExitBtn;// CContainedWindow diverts msgs to another CMessageMap object provided in the construct function.
CODButtonImpl m_ownBtn;
COwerTree m_ownTree;
};
// main.cpp
#include "stdafx.h"
#include "MainDlg.h"
CAppModule _Module;
int WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE /*hPrevInstance*/, LPTSTR /*lpstrCmdLine*/, int nCmdShow)
{
HRESULT hRes = ::CoInitialize(NULL);
ATLASSERT(SUCCEEDED(hRes));
AtlInitCommonControls(ICC_WIN95_CLASSES); // add flags to support other controls
hRes = _Module.Init(NULL, hInstance);
ATLASSERT(SUCCEEDED(hRes));
int nRet = 0;
BOOL bModal = FALSE;
if (bModal)
{
CMainDlg dlgMain;
nRet = (int)dlgMain.DoModal();//use ::DialogBox to create a modal dialog, which is different from MFC using ::CreateDialog to create Non-modal dialogs.
}
else
{
CMessageLoop theLoop;
_Module.AddMessageLoop(&theLoop);
CMainDlg dlgMain;
if (dlgMain.Create(NULL) != NULL)// use ::CreateDialog to create Non-modal dialogs.
{
dlgMain.ShowWindow(nCmdShow);
nRet = theLoop.Run();
}
_Module.RemoveMessageLoop();
}
_Module.Term();
::CoUninitialize();
return nRet;
}
3. 运行结果
看把鼠标移到按钮上方,观察效果,点击按钮看事件响应。
三. 多文档程序
// AboutDlg.h : interface of the CAboutDlg class
//
/////////////////////////////////////////////////////////////////////////////
#pragma once
class CAboutDlg : public CDialogImpl<CAboutDlg>
{
public:
enum { IDD = IDD_ABOUTBOX };//IDD_ABOUTBOX is a Dialog ResourceId
BEGIN_MSG_MAP(CAboutDlg)
MESSAGE_HANDLER(WM_INITDIALOG, OnInitDialog)
COMMAND_ID_HANDLER(IDOK, OnCloseCmd)
COMMAND_ID_HANDLER(IDCANCEL, OnCloseCmd)
END_MSG_MAP()
// Handler prototypes (uncomment arguments if needed):
// LRESULT MessageHandler(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
// LRESULT CommandHandler(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
// LRESULT NotifyHandler(int /*idCtrl*/, LPNMHDR /*pnmh*/, BOOL& /*bHandled*/)
LRESULT OnInitDialog(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
{
CenterWindow(GetParent());
return TRUE;
}
LRESULT OnCloseCmd(WORD /*wNotifyCode*/, WORD wID, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
{
EndDialog(wID);
return 0;
}
};
// View.h : interface of the CView class
//
/////////////////////////////////////////////////////////////////////////////
#pragma once
class CView : public CDialogImpl<CView>
{
public:
enum { IDD = IDD_WTLMDIDEMO_FORM };
BOOL PreTranslateMessage(MSG* pMsg)
{
return CWindow::IsDialogMessage(pMsg);
}
BEGIN_MSG_MAP(CView)
END_MSG_MAP()
// Handler prototypes (uncomment arguments if needed):
// LRESULT MessageHandler(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
// LRESULT CommandHandler(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
// LRESULT NotifyHandler(int /*idCtrl*/, LPNMHDR /*pnmh*/, BOOL& /*bHandled*/)
};
class NoDlgCView : public CWindowImpl<NoDlgCView>// you can use a non dlg view like this.
{
public:
DECLARE_WND_CLASS(NULL)
BOOL PreTranslateMessage(MSG* pMsg);
BEGIN_MSG_MAP(NoDlgCView)
MESSAGE_HANDLER(WM_PAINT, OnPaint)
END_MSG_MAP()
// Handler prototypes (uncomment arguments if needed):
// LRESULT MessageHandler(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
// LRESULT CommandHandler(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
// LRESULT NotifyHandler(int /*idCtrl*/, LPNMHDR /*pnmh*/, BOOL& /*bHandled*/)
LRESULT OnPaint(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/);
};
BOOL NoDlgCView::PreTranslateMessage(MSG* pMsg)
{
pMsg;
return FALSE;
}
LRESULT NoDlgCView::OnPaint(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
{
CPaintDC dc(m_hWnd);
//TODO: Add your drawing code here
return 0;
}
// ChildFrm.h : interface of the CChildFrame class
//
/////////////////////////////////////////////////////////////////////////////
#pragma once
class CChildFrame : public CMDIChildWindowImpl<CChildFrame>
{
public:
DECLARE_FRAME_WND_CLASS(NULL, IDR_MDICHILD)// IDR_MDICHILD is a Menu ResourceId and a Icon ResourceId
CView m_view;
virtual void OnFinalMessage(HWND /*hWnd*/)
{
delete this;
}
BEGIN_MSG_MAP(CChildFrame)
MESSAGE_HANDLER(WM_CREATE, OnCreate)
MESSAGE_HANDLER(WM_FORWARDMSG, OnForwardMsg)
CHAIN_MSG_MAP(CMDIChildWindowImpl<CChildFrame>)
END_MSG_MAP()
// Handler prototypes (uncomment arguments if needed):
// LRESULT MessageHandler(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
// LRESULT CommandHandler(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
// LRESULT NotifyHandler(int /*idCtrl*/, LPNMHDR /*pnmh*/, BOOL& /*bHandled*/)
LRESULT OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
{
m_hWndClient = m_view.Create(m_hWnd);
bHandled = FALSE;
return 1;
}
LRESULT OnForwardMsg(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& /*bHandled*/)
{
LPMSG pMsg = (LPMSG)lParam;
if(CMDIChildWindowImpl<CChildFrame>::PreTranslateMessage(pMsg))
return TRUE;
return m_view.PreTranslateMessage(pMsg);
}
};
// MainFrm.h : interface of the CMainFrame class
//
/////////////////////////////////////////////////////////////////////////////
#pragma once
class CMainFrame :
public CMDIFrameWindowImpl<CMainFrame>,
public CUpdateUI<CMainFrame>,
public CMessageFilter, public CIdleHandler
{
public:
DECLARE_FRAME_WND_CLASS(NULL, IDR_MAINFRAME)//IDR_MAINFRAME is a Menu ResourceId and a Icon ResourceId, you should add 2 sub pop menu items for the first top menu.
CMDICommandBarCtrl m_CmdBar;
virtual BOOL PreTranslateMessage(MSG* pMsg)
{
if(CMDIFrameWindowImpl<CMainFrame>::PreTranslateMessage(pMsg))
return TRUE;
HWND hWnd = MDIGetActive();
if(hWnd != NULL)
return (BOOL)::SendMessage(hWnd, WM_FORWARDMSG, 0, (LPARAM)pMsg);
return FALSE;
}
virtual BOOL OnIdle()
{
UIUpdateToolBar();
return FALSE;
}
BEGIN_UPDATE_UI_MAP(CMainFrame)
UPDATE_ELEMENT(ID_VIEW_TOOLBAR, UPDUI_MENUPOPUP)
UPDATE_ELEMENT(ID_VIEW_STATUS_BAR, UPDUI_MENUPOPUP)
END_UPDATE_UI_MAP()
BEGIN_MSG_MAP(CMainFrame)
MESSAGE_HANDLER(WM_CREATE, OnCreate)
MESSAGE_HANDLER(WM_DESTROY, OnDestroy)
COMMAND_ID_HANDLER(ID_APP_EXIT, OnFileExit)
COMMAND_ID_HANDLER(ID_FILE_NEW, OnFileNew)
COMMAND_ID_HANDLER(ID_VIEW_TOOLBAR, OnViewToolBar)
COMMAND_ID_HANDLER(ID_VIEW_STATUS_BAR, OnViewStatusBar)
COMMAND_ID_HANDLER(ID_APP_ABOUT, OnAppAbout)
COMMAND_ID_HANDLER(ID_WINDOW_CASCADE, OnWindowCascade)
COMMAND_ID_HANDLER(ID_WINDOW_TILE_HORZ, OnWindowTile)
COMMAND_ID_HANDLER(ID_WINDOW_ARRANGE, OnWindowArrangeIcons)
CHAIN_MSG_MAP(CUpdateUI<CMainFrame>)
CHAIN_MSG_MAP(CMDIFrameWindowImpl<CMainFrame>)
END_MSG_MAP()
// Handler prototypes (uncomment arguments if needed):
// LRESULT MessageHandler(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
// LRESULT CommandHandler(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
// LRESULT NotifyHandler(int /*idCtrl*/, LPNMHDR /*pnmh*/, BOOL& /*bHandled*/)
LRESULT OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
{
// create command bar window
HWND hWndCmdBar = m_CmdBar.Create(m_hWnd, rcDefault, NULL, ATL_SIMPLE_CMDBAR_PANE_STYLE);
// attach menu
m_CmdBar.AttachMenu(GetMenu());
// load command bar images
m_CmdBar.LoadImages(IDR_MAINFRAME);//IDR_MAINFRAME is a Icon ResourceId.
// remove old menu
SetMenu(NULL);
HWND hWndToolBar = CreateSimpleToolBarCtrl(m_hWnd, IDR_MAINFRAME, FALSE, ATL_SIMPLE_TOOLBAR_PANE_STYLE);//IDR_MAINFRAME is a Toolbar ResourceId
CreateSimpleReBar(ATL_SIMPLE_REBAR_NOBORDER_STYLE);
AddSimpleReBarBand(hWndCmdBar);
AddSimpleReBarBand(hWndToolBar, NULL, TRUE);
CreateSimpleStatusBar();
CreateMDIClient();
m_CmdBar.SetMDIClient(m_hWndMDIClient);
UIAddToolBar(hWndToolBar);
UISetCheck(ID_VIEW_TOOLBAR, 1);
UISetCheck(ID_VIEW_STATUS_BAR, 1);
// register object for message filtering and idle updates
CMessageLoop* pLoop = _Module.GetMessageLoop();
ATLASSERT(pLoop != NULL);
pLoop->AddMessageFilter(this);
pLoop->AddIdleHandler(this);
return 0;
}
LRESULT OnDestroy(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
{
m_CmdBar.AttachMenu(NULL);
// unregister message filtering and idle updates
CMessageLoop* pLoop = _Module.GetMessageLoop();
ATLASSERT(pLoop != NULL);
pLoop->RemoveMessageFilter(this);
pLoop->RemoveIdleHandler(this);
bHandled = FALSE;
return 1;
}
LRESULT OnFileExit(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
{
PostMessage(WM_CLOSE);
return 0;
}
LRESULT OnFileNew(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
{
CChildFrame* pChild = new CChildFrame;
pChild->CreateEx(m_hWndClient);
// TODO: add code to initialize document
return 0;
}
LRESULT OnViewToolBar(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
{
static BOOL bVisible = TRUE; // initially visible
bVisible = !bVisible;
CReBarCtrl rebar = m_hWndToolBar;
int nBandIndex = rebar.IdToIndex(ATL_IDW_BAND_FIRST + 1); // toolbar is 2nd added band
rebar.ShowBand(nBandIndex, bVisible);
UISetCheck(ID_VIEW_TOOLBAR, bVisible);
UpdateLayout();
return 0;
}
LRESULT OnViewStatusBar(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
{
BOOL bVisible = !::IsWindowVisible(m_hWndStatusBar);
::ShowWindow(m_hWndStatusBar, bVisible ? SW_SHOWNOACTIVATE : SW_HIDE);
UISetCheck(ID_VIEW_STATUS_BAR, bVisible);
UpdateLayout();
return 0;
}
LRESULT OnAppAbout(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
{
CAboutDlg dlg;
dlg.DoModal();
return 0;
}
LRESULT OnWindowCascade(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
{
MDICascade();
return 0;
}
LRESULT OnWindowTile(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
{
MDITile();
return 0;
}
LRESULT OnWindowArrangeIcons(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
{
MDIIconArrange();
return 0;
}
};
// main.cpp : main source file for WtlMdiDemo.exe
//
#include "stdafx.h"
#include <atlframe.h>
#include <atlctrls.h>
#include <atldlgs.h>
#include <atlctrlw.h>
#include "resource.h"
#include "View.h"
#include "aboutdlg.h"
#include "ChildFrm.h"
#include "MainFrm.h"
CAppModule _Module;
int Run(LPTSTR /*lpstrCmdLine*/ = NULL, int nCmdShow = SW_SHOWDEFAULT)
{
CMessageLoop theLoop;
_Module.AddMessageLoop(&theLoop);
CMainFrame wndMain;
if(wndMain.CreateEx() == NULL)
{
ATLTRACE(_T("Main window creation failed!\n"));
return 0;
}
wndMain.ShowWindow(nCmdShow);
int nRet = theLoop.Run();
_Module.RemoveMessageLoop();
return nRet;
}
int WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE /*hPrevInstance*/, LPTSTR lpstrCmdLine, int nCmdShow)
{
HRESULT hRes = ::CoInitialize(NULL);
ATLASSERT(SUCCEEDED(hRes));
AtlInitCommonControls(ICC_COOL_CLASSES | ICC_BAR_CLASSES); // add flags to support other controls
hRes = _Module.Init(NULL, hInstance);
ATLASSERT(SUCCEEDED(hRes));
int nRet = Run(lpstrCmdLine, nCmdShow);
_Module.Term();
::CoUninitialize();
return nRet;
}
四. 单文档程序
// AboutDlg.h : interface of the CAboutDlg class
//
/////////////////////////////////////////////////////////////////////////////
#pragma once
class CAboutDlg : public CDialogImpl<CAboutDlg>
{
public:
enum { IDD = IDD_ABOUTBOX };// IDD_ABOUTBOX is Dialog ResourceId
BEGIN_MSG_MAP(CAboutDlg)
MESSAGE_HANDLER(WM_INITDIALOG, OnInitDialog)
COMMAND_ID_HANDLER(IDOK, OnCloseCmd)
COMMAND_ID_HANDLER(IDCANCEL, OnCloseCmd)
END_MSG_MAP()
// Handler prototypes (uncomment arguments if needed):
// LRESULT MessageHandler(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
// LRESULT CommandHandler(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
// LRESULT NotifyHandler(int /*idCtrl*/, LPNMHDR /*pnmh*/, BOOL& /*bHandled*/)
LRESULT OnInitDialog(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
{
CenterWindow(GetParent());
return TRUE;
}
LRESULT OnCloseCmd(WORD /*wNotifyCode*/, WORD wID, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
{
EndDialog(wID);
return 0;
}
};
// View.h : interface of the CView class
//
/////////////////////////////////////////////////////////////////////////////
#pragma once
class CView : public CDialogImpl<CView>
{
public:
enum { IDD = IDD_WTLSDIDEMO_FORM };//IDD_WTLSDIDEMO_FORM is a Dialog ResourceId
BOOL PreTranslateMessage(MSG* pMsg)
{
return CWindow::IsDialogMessage(pMsg);
}
BEGIN_MSG_MAP(CView)
END_MSG_MAP()
// Handler prototypes (uncomment arguments if needed):
// LRESULT MessageHandler(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
// LRESULT CommandHandler(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
// LRESULT NotifyHandler(int /*idCtrl*/, LPNMHDR /*pnmh*/, BOOL& /*bHandled*/)
};
class NonDlgCView : public CWindowImpl<NonDlgCView>
{
public:
DECLARE_WND_CLASS(NULL)
BOOL PreTranslateMessage(MSG* pMsg);
BEGIN_MSG_MAP(NonDlgCView)
MESSAGE_HANDLER(WM_PAINT, OnPaint)
END_MSG_MAP()
// Handler prototypes (uncomment arguments if needed):
// LRESULT MessageHandler(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
// LRESULT CommandHandler(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
// LRESULT NotifyHandler(int /*idCtrl*/, LPNMHDR /*pnmh*/, BOOL& /*bHandled*/)
LRESULT OnPaint(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/);
};
BOOL NonDlgCView::PreTranslateMessage(MSG* pMsg)
{
pMsg;
return FALSE;
}
LRESULT NonDlgCView::OnPaint(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
{
CPaintDC dc(m_hWnd);
//TODO: Add your drawing code here
return 0;
}
// MainFrm.h : interface of the CMainFrame class
//
/////////////////////////////////////////////////////////////////////////////
#pragma once
class CMainFrame :
public CFrameWindowImpl<CMainFrame>,
public CUpdateUI<CMainFrame>,
public CMessageFilter, public CIdleHandler
{
public:
DECLARE_FRAME_WND_CLASS(NULL, IDR_MAINFRAME)// IDR_MAINFRAME is a Menu ResourceId and a Icon ResourceId, at least 2 sub pop menu items need to be added to the first top menu.
CView m_view;
CCommandBarCtrl m_CmdBar;
virtual BOOL PreTranslateMessage(MSG* pMsg)
{
if(CFrameWindowImpl<CMainFrame>::PreTranslateMessage(pMsg))
return TRUE;
return m_view.PreTranslateMessage(pMsg);
}
virtual BOOL OnIdle()
{
UIUpdateToolBar();
return FALSE;
}
BEGIN_UPDATE_UI_MAP(CMainFrame)
UPDATE_ELEMENT(ID_VIEW_TOOLBAR, UPDUI_MENUPOPUP)
UPDATE_ELEMENT(ID_VIEW_STATUS_BAR, UPDUI_MENUPOPUP)
END_UPDATE_UI_MAP()
BEGIN_MSG_MAP(CMainFrame)
MESSAGE_HANDLER(WM_CREATE, OnCreate)
MESSAGE_HANDLER(WM_DESTROY, OnDestroy)
COMMAND_ID_HANDLER(ID_APP_EXIT, OnFileExit)
COMMAND_ID_HANDLER(ID_FILE_NEW, OnFileNew)
COMMAND_ID_HANDLER(ID_VIEW_TOOLBAR, OnViewToolBar)
COMMAND_ID_HANDLER(ID_VIEW_STATUS_BAR, OnViewStatusBar)
COMMAND_ID_HANDLER(ID_APP_ABOUT, OnAppAbout)
CHAIN_MSG_MAP(CUpdateUI<CMainFrame>)
CHAIN_MSG_MAP(CFrameWindowImpl<CMainFrame>)
END_MSG_MAP()
// Handler prototypes (uncomment arguments if needed):
// LRESULT MessageHandler(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
// LRESULT CommandHandler(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
// LRESULT NotifyHandler(int /*idCtrl*/, LPNMHDR /*pnmh*/, BOOL& /*bHandled*/)
LRESULT OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
{
// create command bar window
HWND hWndCmdBar = m_CmdBar.Create(m_hWnd, rcDefault, NULL, ATL_SIMPLE_CMDBAR_PANE_STYLE);
// attach menu
m_CmdBar.AttachMenu(GetMenu());
// load command bar images
m_CmdBar.LoadImages(IDR_MAINFRAME);//IDR_MAINFRAME is a Icon ResourceId
// remove old menu
SetMenu(NULL);
HWND hWndToolBar = CreateSimpleToolBarCtrl(m_hWnd, IDR_MAINFRAME, FALSE, ATL_SIMPLE_TOOLBAR_PANE_STYLE);//IDR_MAINFRAME is a ToolBar ResourceId
CreateSimpleReBar(ATL_SIMPLE_REBAR_NOBORDER_STYLE);
AddSimpleReBarBand(hWndCmdBar);
AddSimpleReBarBand(hWndToolBar, NULL, TRUE);
CreateSimpleStatusBar();
m_hWndClient = m_view.Create(m_hWnd);
UIAddToolBar(hWndToolBar);
UISetCheck(ID_VIEW_TOOLBAR, 1);
UISetCheck(ID_VIEW_STATUS_BAR, 1);
// register object for message filtering and idle updates
CMessageLoop* pLoop = _Module.GetMessageLoop();
ATLASSERT(pLoop != NULL);
pLoop->AddMessageFilter(this);
pLoop->AddIdleHandler(this);
return 0;
}
LRESULT OnDestroy(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
{
// unregister message filtering and idle updates
CMessageLoop* pLoop = _Module.GetMessageLoop();
ATLASSERT(pLoop != NULL);
pLoop->RemoveMessageFilter(this);
pLoop->RemoveIdleHandler(this);
bHandled = FALSE;
return 1;
}
LRESULT OnFileExit(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
{
PostMessage(WM_CLOSE);
return 0;
}
LRESULT OnFileNew(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
{
// TODO: add code to initialize document
return 0;
}
LRESULT OnViewToolBar(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
{
static BOOL bVisible = TRUE; // initially visible
bVisible = !bVisible;
CReBarCtrl rebar = m_hWndToolBar;
int nBandIndex = rebar.IdToIndex(ATL_IDW_BAND_FIRST + 1); // toolbar is 2nd added band
rebar.ShowBand(nBandIndex, bVisible);
UISetCheck(ID_VIEW_TOOLBAR, bVisible);
UpdateLayout();
return 0;
}
LRESULT OnViewStatusBar(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
{
BOOL bVisible = !::IsWindowVisible(m_hWndStatusBar);
::ShowWindow(m_hWndStatusBar, bVisible ? SW_SHOWNOACTIVATE : SW_HIDE);
UISetCheck(ID_VIEW_STATUS_BAR, bVisible);
UpdateLayout();
return 0;
}
LRESULT OnAppAbout(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
{
CAboutDlg dlg;
dlg.DoModal();
return 0;
}
};
// main.cpp : main source file for WtlSdiDemo.exe
//
#include "stdafx.h"
#include <atlframe.h>
#include <atlctrls.h>
#include <atldlgs.h>
#include <atlctrlw.h>
#include "resource.h"
#include "View.h"
#include "aboutdlg.h"
#include "MainFrm.h"
CAppModule _Module;
int Run(LPTSTR /*lpstrCmdLine*/ = NULL, int nCmdShow = SW_SHOWDEFAULT)
{
CMessageLoop theLoop;
_Module.AddMessageLoop(&theLoop);
CMainFrame wndMain;
if(wndMain.CreateEx() == NULL)
{
ATLTRACE(_T("Main window creation failed!\n"));
return 0;
}
wndMain.ShowWindow(nCmdShow);
int nRet = theLoop.Run();
_Module.RemoveMessageLoop();
return nRet;
}
int WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE /*hPrevInstance*/, LPTSTR lpstrCmdLine, int nCmdShow)
{
HRESULT hRes = ::CoInitialize(NULL);
ATLASSERT(SUCCEEDED(hRes));
AtlInitCommonControls(ICC_COOL_CLASSES | ICC_BAR_CLASSES); // add flags to support other controls
hRes = _Module.Init(NULL, hInstance);
ATLASSERT(SUCCEEDED(hRes));
int nRet = Run(lpstrCmdLine, nCmdShow);
_Module.Term();
::CoUninitialize();
return nRet;
}
参考书籍: