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

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.

Related

MFC: how to fix an MDI after replacing the CView with a CSplitterWnd having two CView-derived classes in the panes

I added a navigation sidebar in my CChildFrame by creating a CSplitterWnd in it and by adding a CScrollView and a CListView as splitter panes based on this answer. Is there a textbook way to do this? I'm asking because I ran into multiple side-effects like the document name no longer showing up in the applications titlebar or mousewheel no longer working for the CScrollView.
I guess, I need to redirect messages arriving in my CChildFrame somehow to make my CScrollView the default receiver for CView-related messages as the CSplitterWnd breaks the flow, because it's not derived from CView. Can someone point me in the right direction?
(Note: This is still done with VS 2008.)
Update: I just created a separate question for the application window title update issue: MFC: After applying a CSplitterWnd to my CChildFrame the main window title isn't updated any more
These code samples are not the most suitable ones, because they create CWnd-derived panes, not CView-derived ones. The views are not in some way associated to the document. You need to call the CDocument::AddView() method, to add every view you created to the document's list of views. The pContext parameter contains a pointer to the document, among other members.
Put the code below in your document class, to verify that your views have been created and associated to the document correctly:
POSITION pos = GetFirstViewPosition();
while (pos)
{
CView *pVw = GetNextView(pos);
AfxMessageBox(typeid(*pVw).name(), MB_OK | MB_ICONINFORMATION);
}
Also in each view class:
CDocument *pDoc = GetDocument();
if (pDoc) AfxMessageBox(pDoc->GetTitle(), MB_OK | MB_ICONINFORMATION);
else AfxMessageBox("The view has no associated Document!");
Note: The default implementation of the CChildFrame class calls CSplitterWnd::Create() rather than CSplitterWnd::CreateStatic() to create the splitter window, and if you move the splitter window to the end it destroys the panes that come off-view. Then if you move it back it creates them again, using the information in the document template or the existing views. You may need to override this behavior too, if you finally make a dynamic splitter window. Better check the MFC source of the version you are using.
There seem to be historical interferences between splitter and view concerning mouse wheel: https://forums.codeguru.com/showthread.php?42826-BUG-CSplitterWnd-Mouse-Wheel
I wont't mark this as solution, as I don't comprehend the backgrounds completely, but it's a workaround for the moment:
BOOL CMyScrollViewDerivedClassInTheStaticSplitter::OnMouseWheel(UINT nFlags, short zDelta, CPoint pt)
{
// CSplitterWnd prohibits mousewheel somehow. Doing it explicitely here:
CPoint pos = GetScrollPosition();
pos.y -= zDelta;
ScrollToPosition(pos);
return CScrollView::OnMouseWheel(nFlags, zDelta, pt);
}

MFC: Notification after a control is created

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.

MFC - Change font in a CMFCToolTipCtrl used in CDialogEx control

I'm trying to display a ToolTip for a CStatic derived control in my dialog.
What I've already done:
Added a CMFCToolTipCtrl item to my CDialogEx member.
In the init dialog member I've specified CMFCToolTipInfo structure and passed it as argument in CMFCToolTipCtrl item constructor.
Call the EnableToolTips(); member for my CStaticExts and for my CDialogEx.
Overrided the PreTranslateMessage of my CDialogEx adding the "RelayEvent".
Set "Notify: TRUE" in the resource editor.
Doing so I managed to display the tooltip in a partially customized way (baloon and background color) but now I would like to enlarge the font, make it bold and, eventually, display an icon, similarly to the tool tips I can see on my toolbar.
I already tried calling "SetFont" and "SetIcon" methods for the CMFCToolTipCtrl item but it didn't work.
Is that possible?
The normal Font that is used in CMFCToolTipCtrl ist retrieved from a global data store inside the MFC (see GetGlobalData()->fontTooltip). This data structure AFX_GLOBAL_DATA is filled when the MFC is started. SetFont has no effect here.
If you want to change the behaviour you have to create your own CMFCToolTipCtrl class and overwrite OnDrawLabel. You have the source of the MFC so it is easy to provide your own implementation.

converting a CView to a CFormView

I have a CView and I've been painting stuff on it just fine. Then I realized I needed to add some controls like text boxes and combo boxes to my CView. So I am trying to convert my CView into a CFormView which does not have a default constructor. But I need a default constructor for this line IMPLEMENT_DYNCREATE(CMyView, CFormView) so I have created a default constructor like this CMyView::CMyView():CFormView( ( UINT )666 ) { ... }. That 666 is because I don't know which argument I am supposed to pass there. I am guessing that I need to pass the ID of my CMyView class. I can't find the id of my CMyView class which was originally created by the Visual Studio project wizard automatically. Where should I look for it? When I run the program I get this error: First-chance exception at 0x75AEC41F in myapp.exe: Microsoft C++ exception: CInvalidArgException at memory location 0x003CF134.
Critical error detected c0000374
myapp.exe has triggered a breakpoint.
And it stops at line 51 in free.c
So my question is: how can I fix this? Also I want to keep the stuff that I previously painted in my former CView, now CFormView. Is the CFormView able to paint like the CView? If not, should I use a split pane in my CMainFrame and have a CView and a CFormView? I might have used terms specific to Java swing and I apologize for that. I am new to MFC and C++.
Thank you in advance,
Corneliu
The CFormView constructor needs the ID of the form's dialog template to be passed in. That is the template you create in the visual editor. You can see how this works by creating a little test project with a CFormView to make your declarations look like the MFC declarations in the test project.
The CFormView can be painted like a CView (in OnDraw), but you might have undesired effects on the controls if you do any scaling or scrolling of the view.
Other alternatives for mixing controls with painted output are (1) Using CControlBar to put controls on the edge of the view or (2) Put a CStatic on the CFormView and do your painting in the CStatic.
Check out Resources.rc.
You can try adding something like this:
IDD_DIALOG1 DIALOG 0, 0, 400, 400
STYLE DS_SETFONT | WS_CHILD
FONT 8, "MS Sans Serif"
BEGIN
END

Using SubclassDlgItem to change control types

I have a C++ MFC app with a dialog where I want to change the type of the control dynamically based on the selection in a combo box. The dialog resource starts off with a plain old edit control which I then call SubclassDlgItem on to change to a custom control type.
So far so good. Now, when the user changes the selection in a different Combobox on the screen, I want to change this control to a different custom type. So, I destroy the existing control by calling delete on the pointer to the custom class for that control. I then call ::CreateEx to re-create my edit control and call SubclassDlgItem again to create the new custom control.
My problem is that this flickers quite a bit, and I think I'm getting the edit control created with ::CreateEx on top of my custom control. Any ideas on how to get rid of the flicker, especially if the user is quickly changing the contents of the controlling combo box?
You can create a set of all possible controls in the same area of the parent window and show only the relevant one and hide all the others. When the user causes the control change you hide the active control and show the new relevant. This should look smoother.
A colleague of mine suggested calling CWnd::LockWindowUpdate() before I do the switch. So, it boils down to something like this:
CRect r;
DWORD dwStyle = WS_CHILD|WS_TABSTOP|WS_VISIBLE;
m_pParent->GetDlgItem(m_nID)->GetWindowRect(&r);
m_pParent->ScreenToClient(r);
m_pParent->LockWindowUpdate();
m_pParent->InvalidateRect(r);
delete m_pCust; // Delete the old custom control
m_pCust = NULL;
::CreateWindowEx(0, "EDIT", "", dwStyle, r.left, r.top, r.Width(), r.Height(), m_pParent->m_hWnd, (HMENU)m_nID, AfxGetInstanceHandle(), NULL);
m_pCust = new CustomCtrl();
pCust->SubclassDlgItem(m_nID, m_pParent);
m_pParent->UnlockWindowUpdate()
There is a little more involed because of what my custom control does. I ended up calling m_pParent->InvalidateRect(r) to get my control to draw correctly at the end.
Also, it turns out that the overlap of the ::CreateEx edit control was because I was calling UnsubclassDlgItem before deleting the old custom control