WTL中所有者绘制的CTabCtrl

时间:2014-01-27 12:16:13

标签: winapi wtl

WTL / WIN32新手在这里,努力了解消息是如何传播的。

我正在尝试在WTL中编写一个所有者绘制的CTabCtrl。对于某些(至少对我而言)难以理解的原因,WM_DRAWITEM被发送到窗口,而不是实际需要知道的窗口。这使得很难创建一个漂亮的,自包含的GUI类来简单地替换CTabCtrl。我总是可以在父节点中捕获消息并将其传递给选项卡控件,但这将是糟糕的OO设计。有没有办法拦截消息,没有在所有者/父类中需要额外的重新路由代码?

编辑:经过一些谷歌搜索,我现在有

class CQueryTabCtrl : 
    public CWindowImpl<CQueryTabCtrl, CTabCtrl>, 
    public COwnerDraw<CQueryTabCtrl>
{
public:
    DECLARE_WND_SUPERCLASS(NULL, CTabCtrl::GetWndClassName())
    BEGIN_MSG_MAP(CQueryTabCtrl)
        CHAIN_MSG_MAP(COwnerDraw<CQueryTabCtrl>)
        DEFAULT_REFLECTION_HANDLER()
    END_MSG_MAP()

    BOOL PreTranslateMessage(MSG* pMsg)
    {
        pMsg;
        return FALSE;
    }

    void DeleteItem(LPDELETEITEMSTRUCT /*lpDeleteItemStruct*/)
    {
    }

    void DrawItem ( LPDRAWITEMSTRUCT lpdis )
    {
        CDCHandle dc = lpdis->hDC;
        CDC dcMem;

        dcMem.CreateCompatibleDC ( dc );
        dc.SaveDC();
        dcMem.SaveDC();

        dc.FillSolidRect ( &lpdis->rcItem, RGB(255,0,0) );

        dcMem.RestoreDC(-1);
        dc.RestoreDC(-1);
    }
};

这显然是完全错误的,因为从不调用DrawItem()。

2 个答案:

答案 0 :(得分:1)

WM_DRAWITEM已发送给父by design

  

当按钮,组合框,列表框或菜单的可视方面发生更改时,发送到所有者绘制按钮,组合框,列表框或菜单的父窗口。

您可以在托管窗口上处理它,使用WTL,您可以在其上使用COwnerDraw类和/或在那里反映消息,以便将它们发送回您的子类WindowProc将处理它们的窗口正如你原先计划的那样。

答案 1 :(得分:0)

这个答案对聚会来说有点晚了,但可能会帮助其他人...

如罗曼指出的那样,没有任何额外的路由代码就无法直接获得反射消息,因为正如罗曼指出的那样,这就是Window的窗口消息传递的工作方式。

但是,ATL具有将消息反映到子窗口的机制,这至少有助于将自行编写的代码保持在最低水平。

1)选择加入反射

这需要在父窗口中执行一个额外的步骤,以告诉它使用REFLECT_NOTIFICATIONS()宏将子窗口中的消息反映到它们上:

// Just a made-up dialog class for outlining message reflection installed on the parent window
class SomeDialog : public CDialogImpl<SomeDialog, CWindow>
{
public:
    BEGIN_MSG_MAP_EX(SomeDialog)
        REFLECT_NOTIFICATIONS()
    END_MSG_MAP()
};

2)处理反映的(所有者绘图)消息

因为您的控件将收到 reflected 消息,并且COwnerDraw混合为这些消息提供了替代消息映射,您只需使用CHAIN_MSG_MAP_ALT()宏将其链接到该消息映射即可。

class CQueryTabCtrl : 
    public CWindowImpl<CQueryTabCtrl, CTabCtrl>, 
    public COwnerDraw<CQueryTabCtrl>
{
public:
    DECLARE_WND_SUPERCLASS(NULL, CTabCtrl::GetWndClassName())

    BEGIN_MSG_MAP(CQueryTabCtrl)
        CHAIN_MSG_MAP_ALT(COwnerDraw<CQueryTabCtrl>, 1)
    END_MSG_MAP()

    void DrawItem(LPDRAWITEMSTRUCT)
    {
        // ...
    }
};

还可以从wtlext存储库中看到完整的owner-drawn tablist control,可以作为示例(免责声明:我与作者FireDaemon Technologies Ltd相关联)。