CTodayWindow - 创建自定义今日项的模板类
一篇关于使用 CTodayWindow 类编写自定义今日项目的文章。

引言
在编写自定义今日项目时,我们总是花费大量时间编写可重复使用的甚至不太“用户友好”的代码。我试图将标准的今日自定义项目封装到一个可以重用并且对于开发人员来说更舒适的类中。
背景
这样做的目的是编写一个类似于 MFC CWnd 类的类。该类封装了今日自定义项目的基本功能,并定义了可由开发人员重写的基本行为。
摘要
类 CTodayWindow 定义如下
class CTodayWindow  
{
public:
    // Member Variables
    HWND m_hWnd;
    // Methods
    CTodayWindow();
    CTodayWindow(HINSTANCE hInstance, 
       LPCTSTR lpszClassName, LPCTSTR lpszWindowName);
    virtual ~CTodayWindow();
    // Main Create method
    BOOL Create(HWND hWndParent, 
       DWORD dwStyle = WS_VISIBLE | WS_CHILD);
    // Update Window
    void RefreshWindow(BOOL bShow = FALSE);
    // Set Methods
    BOOL SetIcon(UINT uID, int xDrawAt = 2, int yDrawAt = 0);
    void SetItemHeight(int nHeight);
    void SetClassInfo(LPCTSTR lpszClassName, LPCTSTR lpszWindowName);
    void SetInstance(HINSTANCE hInstance);
    // Get Methods
    HWND GetParent() {return m_hParentHwnd;};
    int GetItemHeight() {return m_nHeight;};
    HINSTANCE GetInstance() {return m_hInstance;};
    HICON GetIcon() {return m_hIcon;};
    LPCTSTR GetClassName() {return m_lpszClassName;};
    LPCTSTR GetWindowName() {return m_lpszWindowName;};
    // Register/Unregister TodayWindow
    void RegisterTodayClass(WNDPROC wndProc);
    void UnregisterTodayClass();
    // TodayWndProc - main message loop
    virtual LRESULT CALLBACK TodayWndProc(UINT uMsg, 
       WPARAM wParam, LPARAM lParam);
protected:
    BOOL m_bInitialRefresh;
    int m_nHeight;
    POINT m_pointIconPos;
    HWND m_hParentHwnd;
    HICON m_hIcon;
    HINSTANCE m_hInstance;
    LPCTSTR m_lpszClassName;
    LPCTSTR m_lpszWindowName;
    COLORREF m_crTodayText;
    HFONT m_hNormalTodayFont;
    HFONT m_hBoldTodayFont;
    virtual void DrawTodayIcon(HDC hDC, int xPos, int yPos);
    virtual void GetTodayDefaults();
    // Message handlers
    virtual int OnCreate(LPCREATESTRUCT lpCreateStruct);
    virtual void OnDestroy();
    virtual void OnPaint(HDC hDC);
    virtual void OnEraseBkgnd(HDC hDC);
    virtual void OnTodayCustomQueryRefreshCache
        (TODAYLISTITEM *pTodayListItem, BOOL *pResult);
    virtual BOOL OnTodayCustomClearCache(TODAYLISTITEM *pTodayListItem);
    virtual void OnLButtonUp(UINT nFlags, POINT point);
    virtual void OnLButtonDown(UINT nFlags, POINT point);
    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 TodayWndProc(UINT uMsg, WPARAM wParam, LPARAM lParam);
此方法处理一些基本消息,并且我已经定义了一些可以重写的虚方法。在我看来,最常用的消息是
- WM_CREATE
- WM_DESTROY
- WM_PAINT
- WM_ERASEBKGND
- WM_LBUTTONDOWN
- WM_LBUTTONUP
- WM_TODAYCUSTOM_CLEARCACHE
- WM_TODAYCUSTOM_QUERYREFRESHCACHE
- WM_SETTINGCHANGE
这些消息有自己的消息处理程序。特殊行为具有以下处理程序
- WM_PAINT,它首先尝试绘制分配给窗口的图标。此图标必须通过- SetIcon方法设置。
- WM_TODAYCUSTOM_QUERYREFRESHCACHE,它识别今日自定义项目的初始化,并设置存储在- m_nHeight中并由- SetItemHeight方法设置的正确项目高度。
- WM_ERASEBKGND消息处理程序- OnEraseBkgnd绘制项目的透明背景。开发人员可以覆盖此标准行为。
今日自定义项目窗口的创建由以下方式处理
BOOL Create(HWND hWndParent, DWORD dwStyle = WS_VISIBLE | WS_CHILD)
方法。此方法创建一个具有以下属性的窗口
- 在 dwStyle参数中传递的样式
- 在 hWndParent参数中传递的父窗口
- 最初设置为 left = 0,top = 0,width = 屏幕宽度,height = 0 的矩形
- 作为构造函数中的属性传递或由 SetClassInfo方法设置的类和窗口名称
此类还提供今日自定义项目窗口类的(取消)注册。
- 类注册由 void RegisterTodayClass(WNDPROC wndProc)方法提供。该参数是在您的今日自定义项目应用程序中定义的主窗口过程。
- 类注销由 void UnregisterTodayClass()提供
使用代码
使用此类非常简单。只需从 CTodayWindow 类派生您自己的类,并定义您的今日自定义项目行为。然后,编写通常已知的主应用程序逻辑(例如,来自 MSDN)。在 DLLMain 函数中,在将库附加到进程时创建您的类的一个实例。设置项目高度、项目图标等常见属性。在 InitializeCustomItem 函数中,注册您的类,并通过调用 Create 方法创建今日自定义项目窗口。就这样。这是示例代码
// Your derived class
static CMyToday* myToday;
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);
        break;
    case DLL_PROCESS_DETACH :
        myToday->UnregisterTodayClass();
        delete myToday;
        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);
}




