I've got a MFC existing project. The CDocument class can update views even when view is not initially updated. Views are of CFormView type, and I know there will be DoDataExchange() called in CFormView::OnInitialUpdate().
Will this cause problem?
I think, it depends on how you implemented OnUpdate in the view classes of your document. UpdateAllViews is nothing more than an iteration over all views of your document which calls OnUpdate for every view. The base implementation of OnUpdate only invalidates the view rectangle. If you access FormView controls in your OnUpdate methods the result might depend on whether OnInitialUpdate has been called before or not. Otherwise it probably doesn't matter if you call UpdateAllViews before or after OnInitialUpdate.
Related
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
I would like to update the ribbon from the CDocument derived class because the information relevant for ribbon's status is stored there. The was created by the Wizard and edited in resource manager
Some elements (Buttons, checkboxes) can be updated with ON_UPDATE_COMMAND_UI macro.
But I have a headache with update other things like CMFCRibbonComboBox or CMFCRibbonProgressBar because CCmdUI doesn't provide suitable functions to deal with them (ie AddItem)
Other option using GetDlgItem doesn't work, because neither CDocument nor RibbonBar elements are derived from CWnd.
So what is the way to update CMFCRibbonComboBox and others?
I faced a similar problem with combo boxes on a toolbar. The combo box was used to display the current mouse coordinates of a point in "world coordinate" space while the mouse was moved. I derived my own class for the combo and exposed some methods that would update its contents. I then picked the most appropriate point in the code to make the appropriate calls to those methods. That may be during the paint cycle (eg. OnDraw), or, during idle time. A similar approach of deriving and exposing methods should work for you. The only caveat is to pick the correct location to inject your calls to perform the update.
I first tried RogerRowland's solution, but it soon became annoying to add a function to MainFrame for every trifle , then to call AfxGetMainWnd() from document and apply static_cast on it.
Instead I now store pointers to the ProgressBar and the combobox inside the document. I added the methods to CMainFrame to get them and removed the rest.
The only dificulty with it is the fact that the document is constructed before the main window. So I have to delay the initialisation of the mentioned pointers. I solved it by adding setRibbonBarPointers() to the document and calling it from OnInitialUpdate() of the view
Is it fine to change model data internally before displaying views? For example
struct MainWindow : QMainWindow
{
MainWindow()
{
mTreeView->setModel(mModel);
mModel->appendChild(...); // No beginInsertRows() and similars are called
}
};
Although the model is set to the view before changing the model data, the view is not displayed since it is done in the constructor of main window. If the view is updated when it is displayed, I think the code should be okay.
When the model is already connected to one or more views I totally recommend calling the corresponding begin... and end... methods before and after the model modification. Those functions emit the signals which connected views (or proxies) must handle before and after the data is modified. Otherwise, the views may end up in an invalid state.
When no views (or proxies) are connected it is safe to do so.
It is fine to do so - your program will not crash, at least. However when you add new items to the model in the way you show in your example, your view will not display the update, especially if you do not use beginInsertRows().
If you want the view properly show the actual data, try to set model after you insert items in it. Otherwise you will need to call beginInsertRows() and endInsertRows() in your model class.
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.
I have several forms that have common sections and I would like to pull them out into their own resource. Basically I am looking for a way to make a CFormView into a windows control that I can insert into another CFormView.
You can create a modaless dialog from the same resource template and create it on a form view. This means you need to refactor your code so the event handlers can be reused between the dialog and your original form view.
CFormView expects it's parent to be a frame. To remove that dependency you need to override all functions that reference the parent frame, which is tedious to do, and each version of MFC may introduce new functions that references the parent frame.