I am having trouble with message reflection. I am trying to set up my list
control to handle CustomDraw on its own, but also let the parent override it.
(That is, the control gets CustomDraw notifications to handle, then reflects
them to the parent to handle after—if it wants.)
I have ON_NOTIFY_REFLECT_EX(NM_CUSTOMDRAW,OnNMCustomDraw) in the control’s
message map. The handler has a simple switch on the DrawStage to ask for subitem
notifications, makes a change to the colors per subitem, then returns a BOOL.
The parent dialog has ON_NOTIFY(NM_CUSTOMDRAW,IDC_LIST,OnNMCustomDrawList) in
its message map, either enabled (active) or disabled (commented out).
If the control returns TRUE, then it gets all expected notifications, and the
parent gets none whether it has the handler enabled or not. Good.
If the control returns FALSE, then the parent gets notifications as expected.
Good. The control itself however only gets messages if the parent has a handler
(even empty); if the parent does not have a handler (in the message map), then
the control does not get CDDS_ITEMPREPAINT (or CDDS_SUBITEM or CDDS_POSTPAINT,
etc.) notifications. Bad!
This seems like a bug. Why would the list control not get (sub)item
notifications (or postpaint, etc.) if the parent does not have a handler?
The last paragraph of http://www.microsoft.com/msj/1197/c1197.aspx explains
exactly what I want:
“So if you're implementing a specialized control such as a tree control that
handles its own drag/drop notification, but you also want to let the parent see
it, just use ON_NOTIFY_REFLECT_EX and return FALSE from your handler.”
That’s what I’m doing, but if the parent does not have a handler, the control’s
handler doesn’t work. Any ideas?
Thanks.
--
Alec S.
news/alec->synetech/cjb/net
Joseph M. Newcomer [MVP]
email: newc...@flounder.com
Web: http://www.flounder.com
MVP Tips: http://www.flounder.com/mvp_tips.htm
> At this point I would be reduced to single-stepping through the MFC
> window-handler code that handles reflected messages, probably with
> conditional breakpoints set so I didn't go crazy ignoring messages I didn't
> want. For example, I'd determine the window handle and not break unless
> LPARAM was that value. That's all I can suggest right now, because it really
> does sound like a bug.
I don’t know about debugging the MFC internal code, but I just did a test with a
bare project and had the same results: the control does not get subsequent
notifications if it returns FALSE and the parent doesn’t have a handler.
Hopefully someone can figure out what’s wrong and/or a fix and/or a workaround.
(I’m using VS.NET 2003 SP1, and have no idea how to report this as a bug to
someone at Microsoft who would hear it and do something about it.) Here’s the
handlers of the control and dialog, and the debug traces (the last one clearly
shows that the control isn’t getting notifications):
BEGIN_MESSAGE_MAP(CMyLC, CListCtrl)
ON_NOTIFY_REFLECT_EX(NM_CUSTOMDRAW, OnNMCustomdraw)
END_MESSAGE_MAP()
BEGIN_MESSAGE_MAP(CaDlg, CDialog)
…
// This is either active or commented out:
// ON_NOTIFY(NM_CUSTOMDRAW, IDC_LIST, OnNMCustomdrawList)
END_MESSAGE_MAP()
BOOL CMyLC::OnNMCustomdraw(NMHDR *pNMHDR, LRESULT *pResult) {
NMLVCUSTOMDRAW* pLVCD = reinterpret_cast<NMLVCUSTOMDRAW*>(pNMHDR);
CString t=_T("");
t.Format(_T("%s\tdrawstage:%d\titem:%d,%d\n"),
_T("\tCCustList::OnNMCustomDraw"), pLVCD->nmcd.dwDrawStage,
pLVCD->nmcd.dwItemSpec, pLVCD->iSubItem);
TRACE(t);
switch (pLVCD->nmcd.dwDrawStage) {
case CDDS_PREPAINT: *pResult=CDRF_NOTIFYITEMDRAW; break;
case CDDS_ITEM|CDDS_PREPAINT: *pResult=CDRF_NOTIFYSUBITEMDRAW; break;
case CDDS_ITEM|CDDS_PREPAINT|CDDS_SUBITEM:
default: *pResult=CDRF_DODEFAULT; break;
}
return FALSE;
}
void CaDlg::OnNMCustomdrawList(NMHDR *pNMHDR, LRESULT *pResult) {
NMLVCUSTOMDRAW* pLVCD = reinterpret_cast<NMLVCUSTOMDRAW*>(pNMHDR);
CString t=_T("");
t.Format(_T("%s\tdrawstage:%d\titem:%d,%d\n"), _T("CaDlg::OnNMCustomDrawList"),
pLVCD->nmcd.dwDrawStage, pLVCD->nmcd.dwItemSpec, pLVCD->iSubItem);
TRACE(t);
switch (pLVCD->nmcd.dwDrawStage) {
case CDDS_PREPAINT: *pResult=CDRF_NOTIFYITEMDRAW; break;
case CDDS_ITEM|CDDS_PREPAINT: *pResult=CDRF_NOTIFYSUBITEMDRAW; break;
case CDDS_ITEM|CDDS_PREPAINT|CDDS_SUBITEM:
default: *pResult=CDRF_DODEFAULT; break;
}
}
Yes, TRUE (GOOD):
CCustList::OnNMCustomDraw drawstage:1 item:2010419606,0
CCustList::OnNMCustomDraw drawstage:65537 item:0,0
CCustList::OnNMCustomDraw drawstage:196609 item:0,0
CCustList::OnNMCustomDraw drawstage:196609 item:0,1
CCustList::OnNMCustomDraw drawstage:65537 item:1,1
CCustList::OnNMCustomDraw drawstage:196609 item:1,0
CCustList::OnNMCustomDraw drawstage:196609 item:1,1
No, TRUE (GOOD):
CCustList::OnNMCustomDraw drawstage:1 item:2010419606,0
CCustList::OnNMCustomDraw drawstage:65537 item:0,0
CCustList::OnNMCustomDraw drawstage:196609 item:0,0
CCustList::OnNMCustomDraw drawstage:196609 item:0,1
CCustList::OnNMCustomDraw drawstage:65537 item:1,1
CCustList::OnNMCustomDraw drawstage:196609 item:1,0
CCustList::OnNMCustomDraw drawstage:196609 item:1,1
Yes, FALSE (GOOD):
CCustList::OnNMCustomDraw drawstage:1 item:2010419606,0
CaDlg::OnNMCustomDrawList drawstage:1 item:2010419606,0
CCustList::OnNMCustomDraw drawstage:65537 item:0,0
CaDlg::OnNMCustomDrawList drawstage:65537 item:0,0
CCustList::OnNMCustomDraw drawstage:196609 item:0,0
CaDlg::OnNMCustomDrawList drawstage:196609 item:0,0
CCustList::OnNMCustomDraw drawstage:196609 item:0,1
CaDlg::OnNMCustomDrawList drawstage:196609 item:0,1
CCustList::OnNMCustomDraw drawstage:65537 item:1,1
CaDlg::OnNMCustomDrawList drawstage:65537 item:1,1
CCustList::OnNMCustomDraw drawstage:196609 item:1,0
CaDlg::OnNMCustomDrawList drawstage:196609 item:1,0
CCustList::OnNMCustomDraw drawstage:196609 item:1,1
CaDlg::OnNMCustomDrawList drawstage:196609 item:1,1
No, FALSE (BAD!):
CCustList::OnNMCustomDraw drawstage:1 item:2010419606,0
--
Alec S.
news/alec->synetech/cjb/net
> > If the control returns TRUE, then it gets all expected notifications, and
I had similar problems with a listview. after some fruitless efforts i
decides to overload onpaint/onbkerase and generated my own
customdrawing routine. nice side-effect is that you can have
CDDS_PREERASE, too;-) the only drawback is that i didnt know how to
implement CDDF_DODEFAULT, e.g. how "backward-return" something to the
default custom drawing routine.
> Joseph M. Newcomer wrote (in news:p09ji4lic5qo8c140...@4ax.com):
>
> I don’t know about debugging the MFC internal code, but I just did a test
> with a bare project and had the same results: the control does not get
> subsequent notifications if it returns FALSE and the parent doesn’t have a
> handler.
I just did a test with the header control and I think I am on to something. I
set up a CMyDlg dialog that subclasses a CMyLC list control which in turn
subclasses a CMyHeader header control. I then traced the CustomDraw handlers for
each, varying whether they return TRUE or FALSE. Here’s the results (the order
of the handlers called):
CMyHeader TRUE: HEADER
CMyHeader FALSE, CMyList TRUE: HEADER, LIST (alternates)
CMyHeader FALSE, CMyList FALSE, CMyDlg TRUE/FALSE: DIALOG
If I remove the handler from the dialog (OnNotify since it can’t do a direct
handler for the header) then the app doesn’t get any header notifications at
all, anywhere. It seems that the dialog is somehow eating the notifications
before the controls get them when they return FALSE.
Unfortunately returning FALSE is who message reflection works; returning TRUE
doesn’t reflect.
H:1, L:1 - H, H, H, H…
H:1, L:0 - H, H, H, H…
H:0, L:1 - H, L, H, L…
H:0, L:0 - D, D, D, D…
The way I see it is that it should work like this: Windows (W) sends a message
to the header; the header gets the message and reflects it to the list; the list
gets the message and reflects it to the dialog; the dialog gets the message (ie
W->H->L->D). And the chain can be broken by returning TRUE (FALSE would have
made more sense).
As you can see, it seems to work as expected until the last line. I don’t know
if it’s compiler dependant (VS.NET 2003 SP1), so maybe it works with a newer
one—ie, it’s been fixed. I also don’t know if it works in a normal app rather
than a dialog app (it wouldn’t be the first quirk that dialog apps have—like
menus and accelerator keys).
Maybe someone with a newer (or older) VisualStudio can test if message
reflection works.
--
Alec S.
news/alec->synetech/cjb/net
Alec S. wrote (in news:ustBlanT...@TK2MSFTNGP04.phx.gbl):