In MFC how to access CView from CWinAppEx - c++

I do not have great expertise in MFC. I have a MFC application with the basic setup: single document application. Now In the project I have the most standard setup: one ...View class one ...Doc class and one ...WinAppEx class. These three represents the model-view-controller design principle respectively. I do not find a way to access View class from the WinAppEx class.
My actual use case is I have some command line arguments passed to the app. I want to display these arguments on my primary view. To access those arguments I have in my ...WinAppEx::InitInstance() method
CCommandLineInfo cmdInfo;
ParseCommandLine(cmdInfo);
Now I need to pass arguments to the view. I have tried ::GetMainWnd() and traverse its siblings and its children. I also tried ::GetNextDocTemplate() and then ::GetNextDoc() and then ::GetNextView(). I still did not find my ...View instance. Can you please shed some light?

Why do you HAVE to access the view from the application? Why not access the application from the view? From the view class you can call AfxGetApp() and get the command line arguments. Also, for a very simple app, usually there is a global variable defined by the wizard called "theApp".

You may be trying to access the CView before it has been created. At the end of the InitInstance function you can cast the m_pMainWnd to a CMainFrame* and use that pointer to call CMainFrame's GetActiveView() function.

Related

Rewrite CListBox as a CCheckListBox

I am working on a Windows application using MFC and Visual Studio C++ 17.
I have multiple tabs in the application, one of which is currently implemented using CListBox and needs to be reimplemented using CCheckListBox.
CCheckListBox is a child class of CListBox.
I have a vector of unique CString's I want to display in the box.
To start simple, I tried making the tab with CListBox and by using CListBox::AddString(), this worked exactly as I wanted it to. It sorted the strings alphabetically, and automatically added a scroll bar on the side when the vector had too many CString's to display all at once in the list.
However, when swapping the CListBox variable to a CCheckListBox variable, I have come across the error when I press run along the lines of:
Debug Assertion Failed! ..... \mfc\winctrl3.cpp Line: 588
I found this GitHub link that has the winctrl3.cpp file and on line 588, there is a function called OnLButtonDblClk which is somewhat explained here.
The trouble is I am unsure of how to swap a variable from a parent class to a child class. Is it so different for Windows classes? In the courses and programs I have taken and written in the past, switching from a parent to child variable was straightforward but this is quite the opposite !
Any help is appreciated, thank you in advance ! :D
There is no assertion in line 588 of the source file in your link. That github upload dates back to 2014. Why not search the winctrl3.cpp source file in your own Visual Studio installation instead? In my own installation, it is in function PreSubclassWindow() and there is indeed an assertion there:
// CCheckListBoxes must be owner drawn
ASSERT(GetStyle() & (LBS_OWNERDRAWFIXED | LBS_OWNERDRAWVARIABLE));
That is the CCheckListBox must be owner-drawn. Find the CCheckListBox constructor code above, you will notice that it calls the CListBox (parent-class) constructor, applying either of the two owner-drawn styles. Instead, the CListBox constructor calls CWnd::Create() with the "LISTBOX" Windows Class-Name as a parameter. That is, it seems to be a MFC-implemented control, overriding the CListBox class, with an owner-drawn style. There is no mention of a native "Check-ListBox" class or style in the Win32 documentation either. Also the CCheckListBox documentation (in the link you posted) clearly states: CCheckListBox is only for owner-drawn controls because the list contains more than text strings.
Therefore:
If you are creating the control using a resource script, add an owner-drawn style (eg LBS_OWNERDRAWFIXED) to the control (or set the Owner-Drawn property in the property editor).
If you are creating the control programmatically make sure you are calling the CCheckListBox constructor, not the CListBox one.
Not sure what you mean about the scroll-bar (and why you mention it), doesn't the list-box display a scroll-bar automatically (WS_VSCROLL style - or property), do you have to do something on your own?
EDIT:
Forgot to mention, if you are creating the control using a resource script use the Class Wizard to add a member variable (of "Control" type, not "Value") to the dialog class. The new variable must be of type CCheckListBox (MFC class). This will subclass the control. If the old project already had a CListBox member variable change it to CCheckListBox.

MFC: Which CFrameWnd function is called after CView::OnInitalUpdate() is called?

I have an MFC app that uses a CSplitterWnd to create multiple-pane views. That process is done in the CFrameWnd::OnCreateClient() call. After that, at some point, the various views have their CView::OnInitialUpdate() function called. One of the views is a CTreeView and another a CListView with multiple columns that are setup within the OnInitialUpdate(). I need to setup the default CTreeView Item which updates the CListView as well. However, if I set the default within OnInitialUpdate the CListView has not yet setup the various columns. Therefore it seems I need to set the default CTreeView Item after all that is done. I presume I'd do this in some CFrameWnd callback. My question is at what point do I do that?
TIA!
It appears that you have dependencies between your views; that's not right.
The data should be stored in the document (even the current selection, if it supposed to be shared between views).
Than the view that is responsible for the change should call CDocument::UpdateAllViews(). As a result, all other views OnUpdate() will be called.
Please see https://learn.microsoft.com/en-us/cpp/mfc/reference/cview-class?view=vs-2019

How to save layout settings of MFC application?

I understand there are functions that can easily write windows registry, however I found out that in new MFC project created with wizard, some information (like split bar position, visibility of controls) gets stored automatically (or at least I found no CWinApp::Write* calls in the project). Since I have also older projects that don't have this behaviour I need to figure out how to make this without help of project wizard. Would anyone please know how does this work?
The MFC control state saving magic happens in the 'New' MFC Feature Pack, specifically in the SaveState methods, for example CMFCToolBar::SaveState.
To take advantage of this you'll therefore need to upgrade your Toolbars and Menus to use the newer controls and upgrade your application to inherit from CWinAppEx. I recommend that you use a New MFC Wizard based app as a guide on how to upgrade your old MFC app.
Most of the information is saved in CPane::SaveState(), thus if you want state of some component saved, you need to use classes derived from CPane. (for more info here is the class hierarchy).
The process of saving window states is initiated through CFrameImpl::OnClosingMainFrame(). This function in turn calls CWinAppEx::SaveState() which saves some application settings and then ALL instances of CMFCToolBar (they add themselves to global list of CMFCToolBars in call to OnCreate). In a similar way all dockable panes are saved but the list belongs to your main frame. Then positioin and size of your main frame is saved.
CViews and CFrameWnds are somewhat less favored, for what I found and tried out, the only information saved was visibility.
I used that loooong time ago. If I correctly reminds it, you should save the informations you want in a overridden CWinApp::ExitInstance() before calling base class method, and you load them in CWinApp::InitInstance. Be sure to allow for default values, because at first run, there will be nothing to load, and do not forget to call (or copy) base class.

Passing Parameters to MFC View Before OnCreateClient

I have an MFC MDI app based on Doc/View Architecture. The problem is that I want to pass some parameters to the View class from the main frame "before" OnCreateClient is called. I am not sure how I can do that as most of the stuff in the doc/ view architecture is done under the hood.
Vague question can only be met with vague answers. Please clarify what your parameters do. Are they view-specific? Document-specific? Not visible to the user?
If your problem is that you have multiple view classes which all use a shared data structure, you could use make the shared data structure a global variable which you initialize in your CWinApp-derived class. Or you could (multiply-)derive them from (both CView and) a parent class that manages the shared data structure.
You could read your parameters from the Windows registry. You might want to do this to save the sizes of windows, their styles, etc.
I don't see what OnCreateClient has to do with any of it, though. If CView::GetDocument() returns NULL then your CView-derived class shouldn't be trying to draw anything.

How can I place a MFC CFormView inside a CDockablePane?

How can I place a MFC CFormView inside a CDockablePane which was introduced in the VS 2008 MFC Feature Pack?
Check the BCGSoft Samples for doing this with a cview. The class names are a little different but its more or less the same stuff since they provided CDockablePane to Microsoft.
I couldn't find such samples in MFC Feature Pack samples.
All projects containing CFormView are :
TasksPane
TabControl
TabbedView
StatusBarDemo
SetPaneSize
MenuSubSet
But in any of the projects, CFormView is not embedded in CDockablePane.
There is a sample of the feature pack that does this.
However, what I do is the following: I made a CDialog-derived class that I put in the DockablePane. Then I make a CFormView-derived class and make an instance of that a member variable of the dockable pane. Every function that I'm interested in (most likely UpdateView() or whatever it's called), I forward to the CDialog-derived class. That way I can sidestep the difficulties of shoehorning the doc/view structure into my application and still get the benefits.
Actually there are a few ways of doing this.
If you derive your own CFameWnd class and then put an instance of that class in the CDockable pane you now can put whatever type of framework that you want inside of that CFrameWnd derived class.
The trick is to make sure that you are doing the creation in the correct order. If you try to call it to early then your internal views will never be created.
Probably this cab be a clue.
http://www.codeproject.com/KB/toolbars/sizecbar.aspx
Although it doesn't use CDockablePane, concept behind it is same.
I didn't try CDockablePane and CFormView work like the one explained in the page yet, but by taking a glance at it, I feel that things are similar.