Confused: CButton's DrawItem and OnClicked
-
I am a little confused about the DrawItem member function. I have tried to create a button class derived from CButton that displays a bitmap but basically acts like a checkbox control with the pushbutton style. i.e when the button is raised, pushing on the button will cause the button to remain depressed until the next button push. Since, I couldn't find a class for checkbox yet alone one that would support a bitmap, I decided to create my own class from CButton and set the BS_CHECKBOX style. Here's the problem which I'm sure is just my lack of understanding. I got the class working except in order to remain depressed I kept track of my own state from the button's OnClick event and combined with the state passed in DrawItem, I drew the button correctly and everything works great...until I put the button in a toolbar. When in a toolbar the button receives the OnClick event but it doesn't pass or reflect the message back to the toolbar and eventually the framewindow. I'm thinking maybe I shouldn't have used the OnClick event for the button but rather used DrawItem alone but am not sure. I mean, since DrawItem state can be ODS_SELECTED can't I just keep track of whether the button should remain depressed or not in a variable, toggle the state, and draw the button each time ODS_SELECTED is the active state? Not sure if that works the way I think it might. Or, is there some way to use OnChildNotify or some other event to make sure I handle the OnClick event and pass it to my parent (toolbar or framewindow eventually)??? Maybe I should have derived from CBitmapButton and just added this state info. Thanks
-
I am a little confused about the DrawItem member function. I have tried to create a button class derived from CButton that displays a bitmap but basically acts like a checkbox control with the pushbutton style. i.e when the button is raised, pushing on the button will cause the button to remain depressed until the next button push. Since, I couldn't find a class for checkbox yet alone one that would support a bitmap, I decided to create my own class from CButton and set the BS_CHECKBOX style. Here's the problem which I'm sure is just my lack of understanding. I got the class working except in order to remain depressed I kept track of my own state from the button's OnClick event and combined with the state passed in DrawItem, I drew the button correctly and everything works great...until I put the button in a toolbar. When in a toolbar the button receives the OnClick event but it doesn't pass or reflect the message back to the toolbar and eventually the framewindow. I'm thinking maybe I shouldn't have used the OnClick event for the button but rather used DrawItem alone but am not sure. I mean, since DrawItem state can be ODS_SELECTED can't I just keep track of whether the button should remain depressed or not in a variable, toggle the state, and draw the button each time ODS_SELECTED is the active state? Not sure if that works the way I think it might. Or, is there some way to use OnChildNotify or some other event to make sure I handle the OnClick event and pass it to my parent (toolbar or framewindow eventually)??? Maybe I should have derived from CBitmapButton and just added this state info. Thanks
JohnnyG wrote: When in a toolbar the button receives the onclick event but it doesn't pass or reflect the message back to the toolbar and eventually the framewindow. Actually, it's exactly the opposite. The OnClicked (
BN_CLICKED
) notification message is sent to the parent window, or better to the window specified as parent during control creation (the parent window can be changed later). MFC reflects notification messages (either in the form ofWM_NOTIFY
orWM_COMMAND
) back to the child control. The message can or can not be processed by the parent then, in dependence to what message macro you use:ON_xxx_REFLECT
orON_xxx_REFLECT_EX
(where xxx can be NOTIFY or CONTROL). If you use the EX extension the message handler function return value is not void, but a BOOL that specifies if the parent can handle the message as well (TRUE) or not (FALSE). Without EX, the parent is called only if the child does not have an handler for the message. For details see TN062 (Technical Note 62: Message Reflection for Windows Controls) on MSDN. Paolo ------ "airplane is cool, but space shuttle is even better" (J. Kaczorowski) -
JohnnyG wrote: When in a toolbar the button receives the onclick event but it doesn't pass or reflect the message back to the toolbar and eventually the framewindow. Actually, it's exactly the opposite. The OnClicked (
BN_CLICKED
) notification message is sent to the parent window, or better to the window specified as parent during control creation (the parent window can be changed later). MFC reflects notification messages (either in the form ofWM_NOTIFY
orWM_COMMAND
) back to the child control. The message can or can not be processed by the parent then, in dependence to what message macro you use:ON_xxx_REFLECT
orON_xxx_REFLECT_EX
(where xxx can be NOTIFY or CONTROL). If you use the EX extension the message handler function return value is not void, but a BOOL that specifies if the parent can handle the message as well (TRUE) or not (FALSE). Without EX, the parent is called only if the child does not have an handler for the message. For details see TN062 (Technical Note 62: Message Reflection for Windows Controls) on MSDN. Paolo ------ "airplane is cool, but space shuttle is even better" (J. Kaczorowski)Paolo, Thanks, for the reply but I'm still confused. I did read TN062 yesterday and here's part of what it says: If, in your parent window class, you supply a handler for a specific WM_NOTIFY message or a range of WM_NOTIFY messages, your handler will be called only if the child control sending those messages does not have a reflected message handler through ON_NOTIFY_REFLECT(). If you use ON_NOTIFY_REFLECT_EX() in your message map, your message handler may or may not allow the parent window to handle the message. If the handler returns TRUE, the message will be handled by the parent as well, while a call that returns FALSE does not allow the parent to handle it. Note that the reflected message is handled before the notification message. So, If in my derived button class, I have ON_NOTIFY_REFLECT_EX(BN_CLICKED, OnClicked)and in my OnClicked member function I return TRUE. What do I need in the framewindow class or even the toolbar class? I mean do I need WM_NOTIFY message handler in one or both of these class files? Currently, I have nothing there but in my application class I have: ON_COMMAND(ID_VIEW_FREEZE, OnViewFreeze) because the button, toolbar button, and menu ID is the same. This worked fine when I was using just a plain CBitmapButton.
-
Paolo, Thanks, for the reply but I'm still confused. I did read TN062 yesterday and here's part of what it says: If, in your parent window class, you supply a handler for a specific WM_NOTIFY message or a range of WM_NOTIFY messages, your handler will be called only if the child control sending those messages does not have a reflected message handler through ON_NOTIFY_REFLECT(). If you use ON_NOTIFY_REFLECT_EX() in your message map, your message handler may or may not allow the parent window to handle the message. If the handler returns TRUE, the message will be handled by the parent as well, while a call that returns FALSE does not allow the parent to handle it. Note that the reflected message is handled before the notification message. So, If in my derived button class, I have ON_NOTIFY_REFLECT_EX(BN_CLICKED, OnClicked)and in my OnClicked member function I return TRUE. What do I need in the framewindow class or even the toolbar class? I mean do I need WM_NOTIFY message handler in one or both of these class files? Currently, I have nothing there but in my application class I have: ON_COMMAND(ID_VIEW_FREEZE, OnViewFreeze) because the button, toolbar button, and menu ID is the same. This worked fine when I was using just a plain CBitmapButton.
JohnnyG wrote: So, If in my derived button class, I have ON_NOTIFY_REFLECT_EX(BN_CLICKED, onclicked)and in my onclicked member function I return TRUE. That's correct, but the BN_CLICKED notification is sent as a WM_COMMAND message and so the right macro should be ON_CONTROL_REFLECT_EX. For the parent window nothing changes, you handle the notification as usual. The different message macro is used by MFC when looking up the message map, so it knows it has to call both handlers. Paolo ------ Why spend 2 minutes doing it by hand when you can spend all night plus most of the following day writing a system to do it for you?
(Chris Maunder) -
JohnnyG wrote: So, If in my derived button class, I have ON_NOTIFY_REFLECT_EX(BN_CLICKED, onclicked)and in my onclicked member function I return TRUE. That's correct, but the BN_CLICKED notification is sent as a WM_COMMAND message and so the right macro should be ON_CONTROL_REFLECT_EX. For the parent window nothing changes, you handle the notification as usual. The different message macro is used by MFC when looking up the message map, so it knows it has to call both handlers. Paolo ------ Why spend 2 minutes doing it by hand when you can spend all night plus most of the following day writing a system to do it for you?
(Chris Maunder)Actually, I did have ON_CONTROL_REFLECT_EX...but it still doesn't work. I'm pulling hairs here. So, what you're saying is that if I used ON_CONTROL_REFLECT_EX and return TRUE, it should work and there is nothing left to do MFC wise in any of my other source files? I put a breakpoint in my app class for the ID of the button (message handler) which is the same as the menu selection ID. If I do the menu selection, I go in there but if I push the button I don't. Instead, I am going into the onclick event handler. However, the button's ID is the same as the menu selection yet both aren't being called when I press the button. If you want, I can post portions of the source code. Thanks for your help!
-
Actually, I did have ON_CONTROL_REFLECT_EX...but it still doesn't work. I'm pulling hairs here. So, what you're saying is that if I used ON_CONTROL_REFLECT_EX and return TRUE, it should work and there is nothing left to do MFC wise in any of my other source files? I put a breakpoint in my app class for the ID of the button (message handler) which is the same as the menu selection ID. If I do the menu selection, I go in there but if I push the button I don't. Instead, I am going into the onclick event handler. However, the button's ID is the same as the menu selection yet both aren't being called when I press the button. If you want, I can post portions of the source code. Thanks for your help!
JohnnyG wrote: So, what you're saying is that if I used ON_CONTROL_REFLECT_EX and return TRUE, it should work and there is nothing left to do MFC wise in any of my other source files? Yes, exactly. Maybe there's something else that's wrong... JohnnyG wrote: If I do the menu selection, I go in there but if I push the button I don't. Are you sure that notification messages are sent to the frame window and not to the toolbar? I remember in some article I read you have to create the control (it was a combo, but should be the same for a button) as child of the frame (or the window you want to get notifications), then change the parent with
SetParent()
. A simple try to discover if the frame gets the message is commenting out the ON_CONTROL_REFLECT_EX line in the message map. Paolo ------ Why spend 2 minutes doing it by hand when you can spend all night plus most of the following day writing a system to do it for you? - (Chris Maunder)