MFC: Notification after a control is created - mfc

I'm new to MFC. I chose to create an office style MFC app through the wizard in VS2017. I now want to extend CMFCShellTreeCtrl so I created another class with that as the base class. The basics are fine. My issue is that I want to do something like:
whatever MyClass::FuncitonCalledAfterControlCreated(...)
{
SetFlags(GetFlags() | SHCONTF_NONFOLDERS);
ModifyStyle(0x0, TVS_CHECKBOXES);
}
But I'm having trouble figuring out what virtual function to override or am I supposed to do one of those message mapping things? I would guess that whatever it is, it would be common to all controls? Anyway, what would be the appropriate function?
TIA!!

If control is derived from CWnd a WM_CREATE is issued which can be directed to the control via a message map of:
ON_WM_CREATE()
And member function:
afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
If on a dialog resource the WM_CREATE won't occur. Some say you can use PreSubClassWindow but on a case of testing Create(), that call comes BEFORE the CreateWindowEx call so won't work for setting the TVS_CHECKBOX style. I didn't try a CDialog with a tree control and check the call stack.

Related

MFC: Can we extend the CEdit control class behaviour present in CEditView

I read few basics about MFC and I am trying to implement simple editor using CEditView. Please correct if my current understanding is wrong.
CEditView is just a view, physically there won't be any control placed in it.
CEditView is just the area, where user can see and enter the text.
Explicitly no need to place any CEdit control on to the view (like
we put CEdit control on the CDialogView).
CEdit control is just a member of CEditView.(GetEditCtrl()).
Currently CEdit provides so many edit related features. If I want to extend that CEdit member class, is it possible to do it? It's something like:
Class CMyEdit : public CEdit
From MSDN:
You construct a CEdit object in two steps. First, call the CEdit
constructor and then call Create, which creates the Windows edit
control and attaches it to the CEdit object.
I create dummy constructor:
CMyEdit::CMyEdit
{
}
After that I called Create:
virtual BOOL Create(
DWORD dwStyle,
const RECT& rect,
CWnd* pParentWnd,
UINT nID);
//Here I have given dummy CRect and dummy Control ID that is 1;
myEdit->Create(ES_MULTILINE | WS_CHILD |
WS_VISIBLE | WS_TABSTOP |
WS_BORDER,CRect(10, 10, 100, 100), this, 1);
If I create and when I run the program, CEdit control is coming onto the CEditView. But I don't want that physical control onto the CEditView.
Do we need to create method here? Not sure how to extend this CEdit class behaviour without creating the control.
CEditView is a CEdit as a view, In fact In a CEdit and in a CEditView there is a normal Windows API Edit control inside. It is a little trick, that the MFC is using. It creates a simple Edit control, (so there is one window handle), but you can treat this handle via a CView pointer AND a CEdit pointer. When you look into the code, you see that GetEditCtrl just casts the this pointer.
When you create a View with a CEditView you have always a CEdit/Edit control inside... you can't change that.
Sure that you get a new edit control over a CEditView if you create an additional control inside of it.
If you can't create a CMyEditView derived from CView with a CMyEdit inside of it (using the full view).
The easiest way would just be to extend a CEditView to a CMyEditView...
It is not very clear what behavior you are trying to modify but looks like you are aware that in MFC you can create your own custom control. You can override the methods of your CEdit in the custom control class CMyEdit like OnPaint() etc. and achieve the same. You should go through with the tutorial which mentioned in details about the custom controls and then you will get to know what all methods you need to override in your custom controls.

Client Area CMDIFrameWndEx

Good afternoon!
I'm updating my application from CMDIFrameWnd to CMDIFrameWndEx, and faced with the problem of client area of MainFrame.Before I had m_hWndMDIClient, and Subclass to it with my class. Now I have m_wndClientArea, and it brings me only headache! Now I can't Subclass. That's why I tried to do this:
mdiCliWnd_.Attach(m_wndClientArea.Detach());
mdiCliWnd_.Invalidate();
mdiCliWnd_.UpdateWindow();
m_wndClientArea.Attach(mdiCliWnd_.Detach());
But I can't even check how it work,because now I have a problem, that I should give CWnd of my client area to another functions, but m_wndClientArea is protected.
So my questions are : Can I subclass my own class in another way? If I can't, how I should use m_wndClientArea to give it to another functions?
What is the reason for that subclassing?
If it is just about drawing the background, use the new virtual function:
OnEraseMDIClientArea
Otherwise it is no problem to use the standard subclassing.
Because the HWND handle of the mdi client window is already attached to a MFC CWnd class object you can't use the MFC subclassing again.

MFC: Didn't get EN_CHANGE message within derived CEdit

I see very strange behavior of CEdit. In my derived class from CEdit control I need to catch text change event. I do it via ON_CONTROL_REFLECT_EX
class CSomeDerivedEdit : public CEdit
{
DECLARE_DYNAMIC(CSomeDerivedEdit )
public:
CSearchEditCtrl();
protected:
DECLARE_MESSAGE_MAP()
afx_msg BOOL OnEnChange();
...
};
in cpp
IMPLEMENT_DYNAMIC(CSomeDerivedEdit , CEdit)
BEGIN_MESSAGE_MAP(CSomeDerivedEdit , CEdit)
ON_CONTROL_REFLECT_EX(EN_CHANGE, &CSomeDerivedEdit::OnEnChange)
END_MESSAGE_MAP()
This control I create within some list control as child window, when I create it and pass as parent window pointer to list control everything working fine and I get EN_CHANGE events but when I pass as parent window header control of list control events didn't resive.
m_someEdit.Create( WS_CHILDWINDOW|WS_VISIBLE, rcRect, this, IDC_EDIT); here everything fine
m_someEdit.Create( WS_CHILDWINDOW|WS_VISIBLE, rcRect, GetHeaderCtrl(), IDC_EDIT); here also control create fine and I see it , but on_control_reflect didn't called when I type in edit control.
ON_CONTROL_REFLECT_EX can only work, if the receiver of the WM_COMMAND message is also subclassed in the MFC. If it is a pure windows control and not subclassed with the MFC the WM_COMMAND message is never reflected to any child.
Remember: The reflection works, because the MFC first handles a WM_COMMAND message from a child in the parent first and offers it back to the child control. And if not handled the WM_COMMAND message is handled inside the parent. Standard window controls doesn't know reflection and always handle WM_COMMAND messages by itself....
So if the header control is not subclassed by the MFC the reflection will not work.
I think you should read the MSDN. When you derive the class CEdit, you should put the ON_EN_CHANGE message handler between BEGIN_MESSAGE_MAP() and END_MESSAGE_MAP() macros. On the other hand, the OnEnChange function, whose declaration is:
afx_msg void OnEnChange();
does not return a BOOL value. The ON_EN_CHANGE message handler should be like this (from MSDN):
BEGIN_MESSAGE_MAP()
ON_EN_CHANGE(ID_OF_THIS_CONTROL,OnEnChange)
END_MESSAGE_MAP()
Hope this will help you.

Where can I put my MFC Control initialization code

I'm writing an MFC CEdit derived control, and I need to add initialization code once the control's m_hwnd is filled.
Which function can I override or which message can I handle to achieve this?
I tried with OnCreate, but It seems to work only for dialogs
EDIT:
The thing I'm initializing is the edit's cue banner
Thanks
Following Mark Ransom's hint, I finally found a better function to implement my intitialization. While overloading CWnd::SubclassWindow is a good idea, this function is not virtual and it would require a call from the subclass pointer. Calling SubclassWindow from a CWnd* would not work.
I found the function CWnd::PreSubclassWindow. It's virtual and is called just before SubclassWindow. Since m_hwnd is valid there, it is a good place to write the code I need.
In addition, the function is virtual and is called automatically by the framework so I don't need to worry about having the good pointer type
OnCreate doesn't work if the control is on a dialog, because the control is created before it can be subclassed to your window class - that happens in the dialog's DoDataExchange.
You can override CWnd::SubclassWindow and call the base method before your own code.
Depending what exactly you are initializing, you can override OnPaint(), or you can add your initialization code into the OnInitDialog() in the Dialog class that the control is contained in.

What's the correct way to create a subclass of a MFC control?

We layout dialogs using the resource editor. So say I have a RichEditCtrl called IDC_RICH. And I want to link it to an instance of a custom class CMyRichEditCtrl : CRichEditCtrl, without losing the ability to set properties on it in resource editor.
What's the right way? You can certainly get some functionality by creating a DDX-linked variable, and changing the type to CMyRichEditCtrl. But in some cases I see people calling code like:
m_Rich.SubclassDlgItem(IDC_RICH, this));
What's the difference?
EDIT: One problem I'm seeing is that when I override Create(Ex) methods, they don't get called. It's kind of like the control is already created by the time my object gets linked to the resource identifier, pehaps?
DDX_Control() does SubclassWindow() under the hood. SubclassDlgItem is a shortcut for SubclassWindow(GetDlgITem()). Usually (broad generalisation here) the people using SubclassWindow are the ones who picked up that habit before DDX_Control existed (pre-1995 or so?) and never really got into MFC-mode, or people who copy and paste their programs together from blog snippets left and right.
So, use DDX_Control() for clarity, although it will technically not make a difference if you use SubclassDlgItem().
The windows you put on a dialog with the resource editor are created using CreateWindow(Ex) with the first argument set to the class name that is specified in the .rc file. The DDX_ mechanism then associates this instantiated window with the dialog class member in DoDataExchange().
MFC is a layer over Win32 but MFC development doesn't completely shield you from Win32. It's more like a bunch of classes and methods that take away some of the drudgery of MFC and provide some form of object-orientedness. The methods of MFC object aren't the ones that are doing the real work, and much of the framework does things under the hood and doesn't notify the 'upper layer' (i.e., MFC objects) unless that is explicitly hooked up. Create() is such a method that is only there if you want to manually create a control, it's not called by MFC when the object is created. (this is a generalization because sometimes it is, but that's outside of the scope of this discussion).
1> For controls that you put on a dialog with the resource editor, used DDX_Control:
class CMyDlg : public CDialogEx
{
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
public:
CRichEditCtrl m_Rich;
};
void CMyDlg::DoDataExchange(CDataExchange* pDX)
{
CDialogEx::DoDataExchange(pDX);
DDX_Control(pDX, IDC_RICHEDIT1, m_Rich);
}
2> For controls that create manually:
CRichEditCtrl m_Rich;
m_Rich.Create(...);
m_Rich.SubclassDlgItem(IDC_RICH, this));