How can you be notified when the user switches between views? - c++

In an MDI application, when the user switches between views something has to be updated. What's the best message to handle for realizing when this happens?
In my application a document has only one view, but logically I want to get notified when switch is between documents.

You can catch WM_SETFOCUS in CChildFrame (ChildFrm.h). When a user clicks a view window, or sets focus to a view in another manner, this member function can be a bridge to whatever you need to set in the application.

Related

Prompt user to save changes when closing MFC view

I have an MFC MDI application, in which it is possible for documents to have multiple views, and for users to customise and then save layout data for the views. This data is associated with the views, not the documents.
I would like to prompt the users to save if they choose to close a view with unsaved layout changes, and am running into problems, as it seems MFC is only geared towards changes in the document. Here are some approaches I've tried:
Override CDocument::SaveModified function, which gets called by the framework when a document is closed. In this function, I send a message to all the document's views, which can then check for unsaved changes and prompt the user.
Perform the check inside the View's destructor.
Perform the check inside the View's OnClose handler
Each of these approaches has problems. (1) is the best, but it fails to deal with cases where there are several views onto one document, and the user closes one of the views. As the document is still open, SaveModified is not called.
The problem with (2) is that on application shutdown, the application has already disappeard by the time any CView destrutors are called. This can leave an orphan dialog box open on the desktop. This is also the case if I try performing the check inside OnDestroy.
I can't get (3) to work - I can't get my views to respond to WM_CLOSE.
Currently, my best solution is to do both (1) and (2), but this requires some smelly logic to prevent the app from prompting the user to save view changes twice on app shutdown.
Anyone know of a better way of doing this? Where is the correct place to hook in?
I'm not sure if it is your solution, but I have several views that can not close on condition and I handle them in DestroyWindow( ). And a message box there does come up over the app before it closes down. So try using DestroyWindow( ) rather than the destructor.
Concur.
ON_WM_DESTROY()
afx_msg void OnDestroy();
does the trick. It will not prevent the window from closing, but the question didn't request it.

Keyboard messages from child controls

I am currently developing a user interface DLL that uses the WIN32 API. The DLL must work for numerous platforms, XP, WIN CE, etc. I have managed to incorporate docking, anchoring and so on but appear to have a problem regarding owner-drawn buttons. I can draw the button's correct state, focus, clicked, default. However, I cannot receive key notifications. I specifically want to perform a click operation on a button that currently has focus, should the user press enter.
Note that I am using a windows message loop rather than a dialog message loop. I use windows hooks to hook into the window creation and set the user data to 'point' to my control instance. If I test for WM_KEYDOWN in the main message loop I can get a handle to my button control instance and could forward the message to the relevant control. Unfortunately, I am dealing with a lot of legacy code and this may not be an ideal solution.
So, my question is what is the best way forward. Is subclassing the button control's window procedure a viable option or is there an easier way?
Many thanks in advance.
The comments above are correct. The button with focus should be getting the key messages. But buttons don't (by themselves) respond to Enter--they respond to Space. It sounds like what you're missing is the typical dialog keyboard navigation, like Tab key moving the focus and Enter activating the "default" button.
If you've got a typical Windows message pump, and you want the keyboard behavior normally associated with dialogs, then you need to use the IsDialogMessage API in your message loop. This means your window is essentially a "modeless dialog".
Looks like standard window proc subclassing should do the trick. See http://msdn.microsoft.com/en-us/library/windows/desktop/ms633591(v=vs.85).aspx for details.

How does one tell when the state of a child window changes in WTL?

I've written a simple GUI using WTL:
I've got everything figured out as far as setting up the window is concerned, and also wired up the menus and such to call whatever I wish. But I need to know when, for example, someone checks one of the checkboxes in the list view, or when someone clicks on a button.
Do these child windows send a message to the main window notifying of the state change, and is that notification generally consistent between child window types?
Child notifications are typically sent to the parent window in the form of WM_NOTIFY or WM_COMMAND messages.
Some child notifications are common across most control types (e.g. NM_CLICK and NM_CUSTOMDRAW), but in general you'll need to look at the notifications reference for each control type on MSDN to see what's available. To start, the reference for listview notifications are here and the button notifications are here.

CDockablePane as a tabbed document does not send WM_SETFOCUS or WM_MDIACTIVATE

I have a class derived from CDockablePane. I need to do something when the view is focused, so I handle WM_SETFOCUS and it all works nicely most of the time.
But when the pane is docked in Tabbed Document mode (TDI), and the user activates it, the WM_SETFOCUS is not called.
I used Spy and noticed the WM_MDIACTIVATE message is sent to the pane's parent window.
However if I handle WM_MDIACTIVATE inside the pane or inside the mainframe, it does not get called either.
Any ideas what I need to handle?
You may need to inherit the frame class and trigger the sending of a custom message to your views when WM_MDIACTIVATE is received by the frame.

Prevent views stealing focus/setting focus to a view

I have an MFC sdi app that uses a splitter window to contain a tree control alongside the main view showing the data.
When the user selects something in the tree, that view keeps focus until the user deliberately clicks in the main data window. This means that any toolbar buttons associated with the main view are disabled.
Is there any way to programmatically switch focus back to the main view after the user has clicked the tree control? Or am I doing something fundamentally wrong using a CSplitterWnd and 2 views?
You don't want to bring the focus back to the other view as soon as someone clicks the tree: It would make your app unusable. e.g. It would prevent users from navigating through the tree using the keyboard since the tree would never keep the focus long enough.
I you really want the toolbar to keep reflecting the state of your 2nd view (I'm not sure it's a good idea), you have a few options. Make your pick. 2 come to mind:
Your tree view should NOT be a CView. Use a simple CTreeCtrl. Not very nice because it kind of break the doc/view paradigm (e.g. no more tree's OnUpdate() called whenever an UpdateAllViews() is called).
Prevent the tree from becoming the active view. To do so:
2.a. When you view gets the focus (OnSetFocus()):
STATIC_DOWNCAST(CFrameWnd, AfxGetMainWnd())->SetActiveView(pTheOtherView);
2.b. Derive a CMySplitterWnd class from CSplitterWnd, then override CMySplitterWnd::SetActivePane() to prevent it from setting the treeview as the active view.
In all cases, welcome to the wonderful world of MFC internals where diving into the source code is the mandatory daily sport ;-)