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()。
答案 0 :(得分:1)
WM_DRAWITEM
已发送给父by design。
当按钮,组合框,列表框或菜单的可视方面发生更改时,发送到所有者绘制按钮,组合框,列表框或菜单的父窗口。
您可以在托管窗口上处理它,使用WTL,您可以在其上使用COwnerDraw
类和/或在那里反映消息,以便将它们发送回您的子类WindowProc
将处理它们的窗口正如你原先计划的那样。
答案 1 :(得分:0)
这个答案对聚会来说有点晚了,但可能会帮助其他人...
如罗曼指出的那样,没有任何额外的路由代码就无法直接获得反射消息,因为正如罗曼指出的那样,这就是Window的窗口消息传递的工作方式。
但是,ATL具有将消息反映到子窗口的机制,这至少有助于将自行编写的代码保持在最低水平。
这需要在父窗口中执行一个额外的步骤,以告诉它使用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()
};
因为您的控件将收到 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相关联)。