CTodayOptionsDialog - 继续按顺序为CTodayWindow类编写今天的自定义项
一篇关于使用 CTodayOptionsDialog 和 CTodayWindow 类编写自定义今日项目的文章。
引言
昨天,我发表了一篇关于模板今日自定义项目类 CTodayWindow
的文章。这个类提供基本功能,但没有选项对话框支持。本文让开发者可以将 CTodayWindow
类与 CTodayOptionsDialog
一起使用,后者处理选项对话框的基本行为。
返回到 CTodayWindow 类
该源代码也包含CTodayWindow
类。我对这个类进行了一些更改。首先,改进了 TodayWndProc
中的消息处理,以及获取在今日窗口上绘制的文本的默认字体。这些字体存储在成员变量 m_hNormalTodayFont
和 m_hBoldTodayFont
中。这两种字体的默认颜色应该是为今日自定义项目定义的颜色,它存储在成员变量 m_crTodayText
中。这就是目前关于 CTodayWindow
类的全部内容。
背景
这样做的目的是编写一个类似于 MFC CDialog
类的类。这个类封装了今日自定义项目选项对话框的基本功能,并定义了开发者可以重写的基本行为。
摘要
CTodayOptionsDialog
类的定义如下
class CTodayOptionsDialog { public: HWND m_hWnd; CTodayOptionsDialog(); CTodayOptionsDialog(HINSTANCE hInstance, CTodayWindow *pToday, BOOL bFullScreen = TRUE); virtual ~CTodayOptionsDialog(); // Get methods HINSTANCE GetInstance() {return m_hInstance;}; BOOL GetFullScreen() {return m_bFullScreen;}; int GetTitleHeight() {return m_nTitleHeight;}; // Set methods void SetInstance(HINSTANCE hInstance) {m_hInstance = hInstance;}; void SetFullScreen(BOOL bFullScreen) {m_bFullScreen = bFullScreen;}; void SetTitle(LPCTSTR lpszTitle, BOOL bRefresh = FALSE); void SetTitle(UINT nID, BOOL bRefresh = FALSE); // Association with option dialog created by system void AssociateWithOptionsDlg(HWND hWnd); void RefreshWindow(); virtual LRESULT CALLBACK TodayOptionsWndProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam); protected : // Reference to Today plug-in window CTodayWindow *m_pWndTW; BOOL m_bFullScreen; int m_nTitleHeight; LPCTSTR m_lpszTitle; HINSTANCE m_hInstance; HFONT m_hTitleFont; // Methods for better work with controls HWND ItemHandleFromID(UINT nID); BOOL IsButtonChecked(UINT nID); void CheckButton(UINT nID, BOOL bCheck = TRUE); void CheckRadionButton(UINT nIDFirst, UINT nIDLast, UINT nIDToCheck); virtual void DrawDialogTitle(HDC hDC); virtual void GetDefaultTitleFont(); // Message handlers virtual BOOL OnInitDialog(TODAYLISTITEM *ptli); virtual void OnDestroy(); virtual void OnOK(); virtual void OnCancel(); virtual void OnPaint(HDC hDC); virtual void OnActivate(UINT nState, HWND hWndPrevious, BOOL bMinimized); virtual void OnCommand(UINT nID, UINT nNotifyCode, HWND hWndCtrl); virtual void OnSettingChange(UINT nFlags, LPCTSTR lpszSection); virtual LRESULT OnNotify(UINT nID, NMHDR* pNMHDR); virtual LRESULT OnMessage(UINT uMsg, WPARAM wParam, LPARAM lParam); };
基本类信息
正如您所看到的,我已经预先将最近使用的消息定义到消息处理程序中,这些处理程序在派生类中易于使用。您不需要在 WndProc
中编写任何代码,并一遍又一遍地做同样的事情。主要消息循环定义在
LRESULT CALLBACK TodayOptionsWndProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
此方法处理一些基本消息,并且我定义了一些可以重写的虚拟方法。在我看来,最常用的消息是
WM_INITDIALOG
WM_DESTROY
WM_PAINT
WM_NOTIFY
WM_COMMAND
WM_ACTIVATE
WM_SETTINGCHANGE
这些消息有自己的消息处理程序。以下处理程序具有特殊行为
WM_PAINT
首先尝试绘制对话框标题。此标题必须由SetTitle
方法设置。
使用代码
使用此类非常简单。只需从 CTodayOptionsDialog
类派生您自己的类并定义您自己的行为。然后,编写通常已知的主应用程序逻辑(例如,来自 MSDN)。在 DLLMain
函数中,在将库附加到进程时创建您的类的一个实例。在构造函数中,将您的 CTodayWindow
派生类作为参数传递,并设置对话框标题。CTodayOptionsDialog
类对存储在成员变量 m_pWndTW
中的当前今日自定义项目窗口具有引用。这允许开发人员访问和处理今日自定义项目窗口,并在设置选项时更改其属性。唯一需要做的是将此变量强制转换为从 CTodayWindow
类派生的正确的今日自定义项目窗口类,如下所示
BOOL CMyOption::OnInitDialog(TODAYLISTITEM *ptli) { BOOL bResult = CTodayOptionsDialog::OnInitDialog(ptli); CMyToday *pToday = (CMyToday*)m_pWndTW; CheckButton(IDC_CHECK_SHOW_FIRST, pToday->m_bShowFirst); CheckButton(IDC_CHECK_SHOW_SECOND, pToday->m_bShowSecond); CheckButton(IDC_CHECK_SHOW_POWER, pToday->m_bShowPower); return bResult; } void CMyOption::OnOK() { CMyToday *pToday = (CMyToday*)m_pWndTW; pToday->m_bShowFirst = IsButtonChecked(IDC_CHECK_SHOW_FIRST); pToday->m_bShowSecond = IsButtonChecked(IDC_CHECK_SHOW_SECOND); pToday->m_bShowPower = IsButtonChecked(IDC_CHECK_SHOW_POWER); CTodayOptionsDialog::OnOK(); }
DLL 库的初始化以及将今日自定义项目窗口类连接到其选项对话框类的一个示例在此处显示
static CMyToday* myToday; static CMyOption *myOption; BOOL APIENTRY DllMain(HANDLE hModule, DWORD dwReason, LPVOID lpReserved) { switch (dwReason) { case DLL_PROCESS_ATTACH : myToday = new CMyToday((HINSTANCE)hModule, _T("MyTodayClass"), _T("MyTodayWnd")); myToday->SetItemHeight(40); myToday->SetIcon(IDI_APP_ICON); myToday->UnregisterTodayClass(); myOption = new CMyOption((HINSTANCE)hModule, myToday, TRUE); myOption->SetTitle(_T("My Today Options"), FALSE); break; case DLL_PROCESS_DETACH : delete myToday; delete myOption; break; } return TRUE; } HWND InitializeCustomItem(TODAYLISTITEM *ptli, HWND hWndParent) { myToday->RegisterTodayClass((WNDPROC)WndProc); myToday->Create(hWndParent, WS_VISIBLE | WS_CHILD); myToday->RefreshWindow(TRUE); return myToday->m_hWnd; } LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { return myToday->TodayWndProc(uMsg, wParam, lParam); } LRESULT WINAPI CustomItemOptionsDlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) { return myOption->TodayOptionsWndProc(hDlg, message, wParam, lParam); }
备注
这两个类协同工作,使开发者能够以一种“接近” MFC 的风格编写今日自定义项目。有人可能会发现此代码有用,而另一些人可能不会。对于使用今日自定义项目的基本工作,我认为这已经足够了。