![]() |
|
MFC, My own reflected from control |
Billybob
Member #3,136
January 2003
|
I have no idea what this is called, MFC was saying something about Reflected From Control or whatever...umm, well just let me explain: Let's say you have a button on a dialog. You can then go to that dialog's class and setup a handler for the click event on that button, even when the button has its own class. So the click messages are getting to both the button and the dialog the button is in. This is quite a useful feature because it often means you don't have to create a new class for every button, or any control for that matter. But some events are not sent back to the parent. One such event that interests me is the WM_MOUSEMOVE event. This is only sent to the control, it is not sent to the dialog when the mouse is inside the control (a button for example). So I was wondering if it is possible to hack MFC to send this info back to the dialog? This question is mainly aimed at those who know the inner workings of MFC.
|
Rick
Member #3,572
June 2003
![]() |
Quote: This is only sent to the control I don't even see mouse move event available for a button. It's available for the dialog though. If you can find it in the control, just call the dialogs mouse move event from within the controls mouse move (if that exists). [EDIT] ======================================================== |
Wil Renczes
Member #5,921
June 2005
![]() |
A little more context as to what you're trying to do would help, as I'm not sure what exactly you're shooting for. What are you trying to do that makes you want to redirect mouse moves from a button control to the parent dialog? But yes, what you're asking for is possible - you can use SendMessage() to send any message you want to any control that's listening for it. |
Billybob
Member #3,136
January 2003
|
See, that solution requires having a non-default class assigned to the Button or whatever other control. I want to avoid that so I can just have a single function in the dialog the control exists in. I removes a lot of pain and agony that way. Even doing a single non-default class for all the controls is a pain in the butt. Something I could hack into the dialog's header or source would be much better.
|
ABC DEF
Member #5,748
April 2005
|
Reflected From Control? |
Wil Renczes
Member #5,921
June 2005
![]() |
You're still losing me - not sure what you're trying to do exactly. But in essence, you already probably have what you need. Check out the definition of the BEGIN_MESSAGE_MAP macro (right-click - go to Definition, if you can) - my ATL version looks like this: #define BEGIN_MSG_MAP(theClass) \ public: \ BOOL ProcessWindowMessage(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT& lResult, DWORD dwMsgMapID = 0) \ { \ BOOL bHandled = TRUE; \ (hWnd); \ (uMsg); \ (wParam); \ (lParam); \ (lResult); \ (bHandled); \ switch(dwMsgMapID) \ { \ case 0: In other words, you already have a function that is set up to handle every type of possible message that Windows will pump around. The whole reflection thing is a red herring - that's usually for when a dialog's child control is trying to notify the parent that something's going on, and you as the parent want to redirect that message back to the child for whatever reason. Generally, a child control will direct messages to the parent dialog - it has to, since the parent dialog decides what happens based on a click, a scroll, etc. If you want the override for mouse move, you just need to add ON_WM_MOUSEMOVE to your message map... |
Rick
Member #3,572
June 2003
![]() |
Quote: If you want the override for mouse move, you just need to add ON_WM_MOUSEMOVE to your message map... What he wants to do is allot like KeyPreview in VB. Basically when KeyPreview is set to True, the Form gets all key events, even if controls have focus. ie. you press enter in a textbox, and both the textbox and the form get the KeyDown & KeyUp events fired. It seems he wants the controls to fire the Dialogs MouseMove event. At a quick glance I didn't see a button even having a MouseMove event in the ClassWizard, but when I subclassed CButton I noticed it's there, but like he said he doesn't want to do that for all controls that he uses. ======================================================== |
Billybob
Member #3,136
January 2003
|
Wil Renczes: Thanks, that's sorta what I needed to know. So now I know what I wanted to do is impossible, because these classes don't shove mouse move events back to the parent. I can't do that find declare thing because it wants to build some weird stuff and I figure it's best not to what with MSVC being what it is. And Rick, CButton derives from CWnd, so obviously it does have mousemove.
|
Wil Renczes
Member #5,921
June 2005
![]() |
I just bounced this around in my head some more, and remembered something that might fit the bill: CWnd::SubclassDlgItem(). When you use this, you reroute all messages that would normally go to the child control to go first through the parent's message map, so you can intercept them. BOOL CAboutDlg::OnInitDialog() { CDialog::OnInitDialog(); SubclassDlgItem(ID_SOMECONTROL, this); return true; }
|
Mr. Accident
Member #3,508
May 2003
![]() |
It's not at all impossible, William. Maybe I'm not understanding something entirely, though. Is it impossible or impractical for you to simply create a custom button class derived from CButton? Then it would be fairly trivial to handle the message however you need, and pass it to the parent if you so desire. Any window can receive and handle any message that is normally sent to windows. ClassWizard, however, in its infinite wisdom, applies a message filter to CWnd-derived classes, so that it will list certain messages only for certain types of windows. Of course, you can always add the message map entries yourself, but if you want ClassWizard to be able to do it, it's fairly easy. Just go to the "Class Info" tab, and set "Message Filter" to "Window". Now the messages list in the "Message Maps" tab should have a lot more stuff in it. Rick: come on, be fair. MFC can only be as ugly as the underlying Win32 API. ...Oh, wait. In all honesty, though, I've been using Visual Studio 6 and MFC for Windows programming for nearly six years now, and I've found it to be more than adequate. I wouldn't use MSVC for much else besides writing Windows apps, naturally, but it gets the job done, and I suppose I'm used to it. MFC itself certainly has its quirks (a LOT of quirks), but I've always managed to get it to do what I wanted to do with relatively little hassle.
|
Wetimer
Member #1,622
November 2001
|
I know nothing about MFC, but could you make a template? I.e. Reflected<CButton> button; <code>if(Windows.State = Crash) Computer.halt();</code> |
Mr. Accident
Member #3,508
May 2003
![]() |
Wil Renczes said: CWnd::SubclassDlgItem(). When you use this, you reroute all messages that would normally go to the child control to go first through the parent's message map, so you can intercept them. BOOL CAboutDlg::OnInitDialog() { CDialog::OnInitDialog(); SubclassDlgItem(ID_SOMECONTROL, this); return true; }
That's not quite how SubclassDlgItem works. It doesn't route messages through the parent's message map, it gives them to the window procedure of the window for which SubclassDlgItem is called. In this case, you don't want to subclass your button to your dialog. This code will produce an assertion failure right away. SubclassDlgItem simply gets the window associated with the control ID and calls SubclassWindow. CWnd::SubclassWindow tries to attach the control HWND to the CWnd object, and CWnd::Attach asserts because your dialog already has a window attached to it. To properly use SubclassDlgItem, you should set up a class that will intercept your messages. I've dressed up the basic example from MSDN to show you what I mean:
This will dynamically subclass the button to the CMyButton object, which will then receive its messages. The CMyButton::OnMouseMove() handler will be called when the cursor moves across the button, and the coordinates (relative to the upper-left corner of the button) will be displayed as the button's caption.
|
Billybob
Member #3,136
January 2003
|
Can a single button be subclass'd to multiple classes?
|
Mr. Accident
Member #3,508
May 2003
![]() |
No, it can't; not dynamically, anyway. If I understand what you mean correctly, the closest thing would be creating a class using multiple inheritance, deriving from both CButton and some other class. I'm not sure why you'd want to do that, though. Multiple inheritance of any sort is usually best avoided, unless you have a really compelling reason to use it.
|
Rick
Member #3,572
June 2003
![]() |
To have VC handle this: Goto class wizard Now in your message maps you will see MyButton, and all available events. Find WM_MOUSEMOVE, add it, Edit code. Now the only thing I want to know how to do is be able to add it via the dialog editor and not via code. But as stated above you can add it via code. ======================================================== |
Mr. Accident
Member #3,508
May 2003
![]() |
You can't make your button an instance of a custom class in the dialog editor. Probably the easiest way is to use ClassWizard to add a member variable for your button. If you've added your custom button class using ClassWizard, you will be able to select your custom class as the type in the "Add Member Variable" dialog. Otherwise, you can just open your dialog's header file and change the variable to be an instance of your custom class instead of CButton.
|
Rick
Member #3,572
June 2003
![]() |
Ah there ya go William. Do the subclass like I said. Then put a normal button on you dialog. Then add a member variable to you dialog of type your new button class. If you put in a mouse move event, it will fire for that button in your buttons class. That is half the battle. Then you could use signal/slot to pass that up to your dialog, or there is probably another way. ======================================================== |
Mr. Accident
Member #3,508
May 2003
![]() |
Well, if you use SubclassDlgItem, there's no need to add a member variable with ClassWizard. Likewise, if you simply use ClassWizard / member variable approach, you don't need to actually call SubclassDlgItem - the subclassing of the button is handled by DDX. EDIT: I should probably clarify myself a bit here. The two approaches are essentially the same thing. It's just that in the latter case, ClassWizard handles the work, and uses the DDX functions instead of just calling SubclassWindow directly. (Also, when I said there's no need to add a member variable, that's not really what I meant - you do need an instance of your custom class to subclass to, of course.) I'm just not explaining myself well. EDIT2: William Heatley said: See, that solution requires having a non-default class assigned to the Button or whatever other control. I want to avoid that so I can just have a single function in the dialog the control exists in. I removes a lot of pain and agony that way. Even doing a single non-default class for all the controls is a pain in the butt. Something I could hack into the dialog's header or source would be much better. Oop, I think I missed this somehow the first time I read this thread. May I ask why it is so difficult in this case to create a custom class for a button? If you're really dead set against creating a new button class, one fairly easy hack would be to simply use the main dialog's OnMouseMove handler, and compare the cursor coordinates to the button rectangle. Honestly, though, it's better to just derive from CButton. MFC classes were meant to be used as base classes when you want to add functionality of your own!
|
Billybob
Member #3,136
January 2003
|
Quote: If you're really dead set against creating a new button class, one fairly easy hack would be to simply use the main dialog's OnMouseMove handler, and compare the cursor coordinates to the button rectangle. You can't. The dialog doesn't get the mouse move event when the mouse is over the button.
|
Mr. Accident
Member #3,508
May 2003
![]() |
Whoops, duh. I forgot about that little detail for some reason.
|
|