Custom MFC control contains another control - messages not getting through - mfc

I have a custom CWnd-derived MFC control, which works like this:
the control has its own OnPaint, and a black background
clicking anywhere on the control causes an edit control to appear at that location, borderless and with black-background, so it blends in
the user types in this box and hits enter, the box disappears and the control's custom paint functionality renders the same text in the same position on the background.
So our control owns a CCustomEdit, when you click on the background the control is either created or moved, and made visible:
CCustomEdit::Show(Rect &rc,CCustomControl *pParent)
{
if ( !::IsWindow( m_hWnd ) )
{
Create( ES_LEFT | ES_AUTOHSCROLL | WS_CHILD | ES_NOHIDESEL | ES_CENTER | ES_UPPERCASE, rc, pParent, 999 );
}
else
MoveWindow( &rc );
}
The main parts actually work OK (and we're stuck with the approach). But one thing that's not working is that CCustomEdit self-registers for EN_CHANGE events and so on. When CCustomEdit is created as a normal dialog control (CEdit on the dialog template, DDX-bound to a CCustomEdit variable) these work, but within CCustomControl they are not.
CCustomEdit::PreSubclassWindow() calls SetEventmask() and is being called. And CCustomEdit's ON_CHAR handler is also being called for key-presses in the edit box, however the handlers for edit-box messages like EN_CHANGE are not.
Are there any obvious things like changing the style flags? Otherwise, why is my custom control stopping these events reaching the contained edit control?

I'm not sure I understand the situation, but I have a number of control that work roughly in the same way as what I think is happening and they all work, it is possible.
EN_CHANGE for the edit control is send to your CWnd-derived control. Are you reflecting the messages? Have you tried if EN_CHANGE gets to the custom control? From what you are describing, you are expecting EN_CHANGE to end up in CCustomEdit's message dispatcher macro chain automatically, but it doesn't; you need the help of the containing window. Now MFC does most of that for you in a CDialog, but if you roll your own you need to do it manually, or use the message reflection macro's.

I found it... somehow, my SetEventMask() was being overriden. I don't know how or where but when I added an extra call later on to test, most event handlers started getting called.
I can only assume some part of the init code in MFC is responsible.

Related

I have a CEdit box. When I disable the box and immediately after try to call SetReadOnly, it stays disabled. Why is this?

There's not a particular reason I'm wanting to do this, it's more for my knowledge of how this stuff works.
I have an edit box derived from CWnd. Let's call it m_edtBox.
When I call m_edtBox.EnableWindow(FALSE)
followed immediately by
m_edtBox.SetReadOnly(TRUE),
the box stays disabled. It does not take on the read-only property. I'm simply curious as to why this is?
A disabled window is a window that
receives no keyboard or mouse input from the user [...].
In other words, the WS_DISABLED window style controls, whether a control gets to handle user input at all.
Contrast that with the ES_READONLY edit control style. It controls which user input that has an effect on the control.
Prevents the user from typing or editing text in the edit control.
Both styles can be set independently, and although both relate to user input, they serve different purposes.

How can I create a Spin Button Control dynamically in MFC using CSpinButtonCtrl class?

I realize that this is a trivial problem and I even looked at an MFC book(Programming Windows with MFC by Prosise). However, I couldn't really find a solution.
I am trying to create a Spin Button Control dynamically and here is a simplified code:
CEdit* m_editControl = new CEdit();
m_EditControl->Create(WS_VISIBLE | WS_CHILD , rectEdit, this, EditID);
CSpinButtonCtrl* m_spinControlCtrl = new CSpinButtonCtrl;
m_spinControlCtrl->Create(WS_VISIBLE | WS_CHILD, rectSpinButton, this, SpinID);
m_spinControlCtrl->SetBase(10);
m_spinControlCtrl->SetBuddy(m_editControl );
m_spinControlCtrl->SetRange(-55, 55);
My problem is that the spin button does not change the value of the CEdit. Am I missing something? How can I create a Spin Button Control dynamically?
Your spin control is missing the style UDS_SETBUDDYINT:
UDS_SETBUDDYINT Causes the up-down control to set the text of the
buddy window (using the WM_SETTEXT message) when the position changes.
The text consists of the position formatted as a decimal or
hexadecimal string.
I also suggest setting UDS_ARROWKEYS so the arrow keys can be used to increment or decrement the value when the focus is on the edit control.
For the edit control I would add WS_TABSTOP so the user can navigate using the TAB key and WS_EX_CLIENTEDGE so the edit control shows the regular themed border.
I also noticed that you use dynamic memory allocation for the controls, which is not necessary. Just create non-pointer member variables like CEdit m_EditControl; so you don't have to worry about deallocation.
Fixed code:
m_EditControl.CreateEx(WS_EX_CLIENTEDGE, L"Edit", L"0", WS_VISIBLE|WS_CHILD|WS_TABSTOP,
rectEdit, this, EditID);
m_spinControlCtrl.Create(WS_VISIBLE|WS_CHILD|UDS_SETBUDDYINT|UDS_ARROWKEYS,
rectSpinButton, this, SpinID);
m_spinControlCtrl.SetBase(10);
m_spinControlCtrl.SetBuddy(&m_EditControl);
m_spinControlCtrl.SetRange(-55, 55);
I also strongly suggest learning to use Spy++. This is how I actually arrived at this answer. Using the resource editor I just dropped an edit control and an up-down control onto a dialog and used Spy++ to observe the default window styles.

Setting focus to the parent window in the OnShowWindow of the child window doesn't work

Generally I have some button that opens child window and the second press on this button should close it. I use a touch screen.
The problem is when I try to press the button for closing the child window, it is not pressed the first time, so I need another click.
In order to fix this I am trying to return the focus to the parent window after the child window is opened.
I register the OnShowWindow message and call SetFocus on the parent window:
void CFlashGuidanceSteps::OnShowWindow(BOOL bShow, UINT nStatus)
{
CDialog::OnShowWindow(bShow, nStatus);
GetParent()->SetFocus();
}
While the function is called (I can see it in debugger), the focus is not returned to the parent window.
However, it works with the OnSetFocus event:
void CFlashGuidanceSteps::OnSetFocus(CWnd* pOldWnd)
{
CDialog::OnSetFocus(pOldWnd);
GetParent()->SetFocus();
}
Why is the focus is not retained with the OnShowWindow event?
The explanation
The usual rule in MFC is that OnXxx functions are called in response to similarly named window messages, e.g. WM_Xxx. So OnShowWindow would be called in response to WM_SHOWWINDOW.
And according to the documentation, WM_SHOWWINDOW is
Sent to a window when the window is about to be hidden or shown.
That means it is sent before the window is actually shown. So when you set the focus to the parent window inside of the OnShowWindow function, nothing actually happens because the parent window already has the focus. Then, after OnShowWindow finishes running, the child window is displayed and demands the focus. It is as if you never made any attempt to change the focus.
By contrast, OnSetFocus, which corresponds to WM_SETFOCUS, is not called until after the window has gained the focus. So when you reassign the focus here, it works because the child window doesn't steal the focus back.
The better idea
That explains the behavior you are seeing, and as you know, things work fine when you adjust the focus in OnSetFocus. But this really isn't the best way of solving the problem.
Manually changing the focus when a window gets and/or loses the focus is approaching the problem the wrong way around, and generally error-prone. You'll get all kinds of focus-related bugs that are difficult to debug. You are better off looking for ways to prevent the focus from changing when you don't want it to.
It sounds to me like you want to prevent the child window from getting the focus when it is created. And there is a way to do precisely that.
When you display the child window, presumably by calling the ShowWindow function or its moral equivalent in MFC, you should pass the SW_SHOWNA flag. That causes the window to be shown without activating it (i.e., granting it the focus).

CHtmlEditCtrl::OnSetFocus not being called

I have derived the CHtmlEditCtrl, and want to be able to react when the control gets or looses its focus. However the standard MFC OnSetFocus and OnKillFocus handling routines are not being called.
I presume it has something to do with the control actualy being a wrapped ActiveX control.
I have tried giving it the WS_EX_CONTROLPARENT and WS_TABSTOP styles on creation as suggested here, but it did not help.
I found somewhere that I should make my control the event sink for HTMLDocumentEvents2, but I would rather avoid that if possible.
EDIT: Spy++ says I should be getting WM_PARENTNOTIFY and WM_MOUSEACTIVATE messages. However, my Derived Class receives absolutely no messages. I tried it with OnSize and OnCreate too. No message whatsoever is being sent. Any idea?

C++/Win32 API - SetFocus to button does not work

HWND button = CreateWindowEx(0, "BUTTON", ...);
SetFocus(button); // Button no get focus! :(
Also, I have other controls on my form that I am able to SetFocus() to.
Thanks, Martin
It has been FOREVER since I've had to do this, but...
Were this a dialog, I would tell you to send a WM_NEXTDLGCTL via PostMessage(). The default dialog item message handler would take care of the rest for you setting keyboard focus and selection activation. However, this is a different case if I read this correctly. You're creating both parent and child windows raw on the fly. If this is the case, SetFocus() to the parent window, and handle WM_SETFOCUS on the parent window by bringing it to top, then setting focus on the child window. WM_SETFOCUS, and WM_KILLFOCUS were designed to allow you to switch the 'activated' state of your controls, and most handle it for you (unless your window is an owner draw control or some such). But in a raw window, when your base parent window is sent the focus, you need to appropriately ensure the proper child has it if you're hosting any (think of it as managing your own 'dialog'). Again, normally this is done by the default dialog procedure for you if this were a dialog, but being raw windows you're kind of stuck managing it all yourself.
Though I can't imagine how, I hope that helped somewhat.
SetFocus is a function, not a procedure. Call it as a function and check its returned value. Either the retuned value is null because you made an error in the CreateWindowEx() call and "button" isn't a valid handle or it's a window not associated with your thread's message queue, or the return value is not null (it's now the prior focused window's handle) and you do have the focus (but are somehow failing to detect it).
Try setting the WS_TABSTOP style on the button.
If you create that button in respond of the WM_INITDIALOG message you should return FALSE to prevent dialog box procedure to change the focus.