Tab Order with CTabCtrl and child CFormViews - c++

In my application I have a CFormView with a CTabCtrl, I also have 4 CFormViews that are children of the main CFormView and that are shown/hidden when the user changes the selected tab.
However, I can't find a way to make the Tab Order to work properly. If the CTabCtrl has the focus, pressing the Tab key has no effect and if one of the child CFormView has the focus the Tab key will move the focus only around the controls inside the CFormView.
I tried changing the z-order of the visible child CFormView to be right after the CTabCtrl with SetWindowPos, changed the child CFormViews styles to WS_EX_CONTROLPARENT but nothing seems to work.

You've started out from the wrong implementation: you shouldn't make a CFormView with a CTabCtrl and then stuff more CFormViews into it. This isn't going to work right. Instead, you should work with CPropertySheet and CPropertyPage, where focus handling has already been taken care of. You will still be able to access the CTabCtrl owned by the CPropertySheet by calling GetTabControl(), but MFC will take care of the problems you've encountered.
Briefly: derive classes from CPropertySheet for each of the dialog windows you want to show (e.g., CConfigPage1, CConfigPage2). Create a Dialog resource in the Resource Editor for each of them, and do all of the other standard CDialog setup.
Next, derive a class from CPropertySheet (e.g., CProps), and (optionally) handle WM_SIZE and TCN_SELCHANGE.
Finally, derive a class from a CView descendent, like CScrollView (e.g., CViewMyAwesomeStuff). Then add member variables for the CPropertySheet and CPropertyPages, and handle WM_CREATE where you Add() each page to the property sheet and then Create(this,WS_CHILD|WS_VISIBLE) the property sheet.
Bonus: You can forward the CView::OnUpdate to each child CPropertyPage by calling GetPage() in a loop and calling a function on each of them, or you can send a message to each of them (use a user-defined message, like WM_APP+1). They can discover their parent's CDocument by calling GetParent()->GetParent()->GetDocument().

Related

Adding CDialog inside CDockablePane and application becomes unresponsive

I want to add a CDialog control inside CDockablePane. When I use CDialog.DoModal() to display the dialog window, it makes the MFC application unresponsive and waiting for the CDialog result.
How can I make the application display the dialog and continue running without waiting for the CDialog result?
You cannot use DoModal to display the dialog. That displays a modal dialog, which prevents interaction with any other windows in your application until the dialog has been dismissed. Just like a message box does.
To display a non-modal dialog, you call the Create member function. Use the instance of your CDockablePane as the dialog's parent. You will also need to ensure that the dialog itself is a child window, without a border.
It might be easier to use a class derived from CFormView or CPaneDialog.

MFC one parent dialog, multiple child dialogs

I want to build a MFC application, with one main dialog, and all the other dialogs are child of this main dialog (and embedded in it).
Now, i was able to embed the first child in the main dialog, but i want to pass to the next dialog (note that the order of opened dialogs is random), so i need to hide the first dialog and show another. To know which dialog is shown at the moment and hide it, i've tried using a CDialog variable to store the current opened dialog, but i get a CObject::operator =' : cannot access private member declared in class 'CObject' error.
Is there another way to do this "hide and show dialogs" game?
EDIT: Could i store some ID of the dialogs and use it to acomplish this task?
So i managed to accomplish this task using classes IDDs.
First, i store the last opened dialog's IDD
m_dlgStartPage.Create(CStartPageDlg::IDD, this);
m_openedWin.nDialogIDD = m_dlgStartPage.IDD;
m_dlgStartPage.ShowWindow(SW_SHOW);
Then, when a new dialog needs to be shown, i send a message to my main dialog (nIDD is the IDD of pending dialog to show):
AfxGetApp()->m_pMainWnd->SendMessage(WM_COMMAND_CHANGE_WINDOW, nIDD, 0);
And last, in my main dialog, i parse all the child dialogs and check if m_openedWin.nDialogIDD matches with each dialog's IDD, so i can hide it. After this, i parse once again all the chid dialogs and use the nIDD from the sent message to show the correct one.
I don't really like this approach, because of all the parsing and sent messages to the main dialog's class, so if anyone has a better idea or method, please post it.

Preventing Mouse-wheel scrolling of controls

I am developing an application using the MFC library and I am currently trying to prevent the user accidentally changing one of the combo box controls when they are scrolling the mouse wheel.
I am looking for a solution without deriving a new class from the CComboBox class and preventing the mouse scrolling there.
My understanding of the system is that Windows passes the WM_MOUSEWHEEL message to the Combo box control which handles it (scrolling the combo box) and then this is propagated up the chain of parent controls (so them to my CFormView etc.), which means I cannot prevent the scrolling by capturing the event in my form view.
Does anyone have a solution to this problem? Thanks in advance!
You can always derive a control from CComboBox and trap the WM_MOUSEWHEEL message in the control itself. Then simply use your new derived combo box in your form view.
If you don't want to create a derived class (perhaps it's too big a change for your project), you can subclass the combo box and trap the WM_MOUSEWHEEL there.
Override the PreTranslateMessage handler in the main window class and look for WM_MOUSEWHEEL messages. Compare the pMsg->hwnd handle in PreTranslateMessage handler with the combobox handle, if found, filter the messages away.

wxDialog with the wxMenuBar

I have tons of existing code using wxWidgets. The main window is wxDialog. Now I have to add a wxMenuBar to that dialog. But, in order to do it, the window should be derived from wxFrame.
Is it possible to add a wxMenuBar to the wxDialog?
If not, is it possible to convert existing code in a way that main window is derived from wxFrame instead from wxDialog?
It's not possible to add a native menu bar to a wxDialog, however, it is possible to use a non-native menu bar control like wxFlatMenuBar (not included with wxWidgets), and add it to the top of the dialog as if it was just another control. Also note though that besides being a non-native menu bar, you also won't be able to use some wxWidgets API to manage it like wxUpdateUIEvents.
There's at least a couple things you will need to take into consideration when changing a wxDialog to a wxFrame.
First, if your dialog is a modal dialog, you will need to manually set the new frame as modal (using wxWindow::MakeModal()) rather than calling ShowModal().
Second, if you had any event handlers setup for the affirmative (OK/Apply button for example) or escape (Cancel or window close) events, you will likely need to rewrite them to handle changes in window behavior.

Parent notification in MFC Dialog

I have a first dialog with a simple button on it and while clicking the button, a second dialog is created using CDialog::Create(IDD,this). I would like the parent to be notified when the second dialog is destroyed but without adding any code to the second dialog i.e., without adding a m_pParent->Notify() line in OnDestroy method.
I have tried OnParentNotify, PreTranslateMessage, SubclassWindow in the parent dialog with no success. I have not used the WS_CHILD style for the second dialog. Any idea?
To complete: in fact, I have a ComboBox derived class (but the issue is the same with buttons) and I'm displaying a modeless Dialog instead of displaying the listbox. But I would like the control to be as generic as possible so that any modeless dialog could be used. That's why I do not want to add a specific notification in the second dialog. If I'm obliged, I will use this trick but I asked for a more generic solution. PreTranslateMessage only catches WM_PAINT, WM_NCMOUSELEAVE and WM_NCMOUSEMOVE.
Use a base class and have your parent refer to the modeless child by base class only. In the base PostNcDestroy have it post to the parent.
It doesn't make sense to have the parent do a bunch of filtering / spying on all messages. It does make sense to implement behavior in a base class that you want to have common to all the different future flavors you might have of the modeless child.
OnParentNotify() is not called since dialog2 is not a child of dialog1.
PreTranslateMessage() should help here (although I don't like this bullet). The trick is that a modeless dialog doesn't destroy itself when it's closed. If you want the dialog to die, it must call DestroyWindow() when it closes, such in an OnCancel() override.
Of course, the first thing that comes to mind is t wonder why you don't want to add custom notification in your modeless dialog code.
EDIT: Another method would consist in installing a message hook (for the current thread, Not the whole system!). This would help you catch all messages for all windows associated to the same thread as dialog1. See SetWindowsHookEx()
How about posting a main parent form event to the message queue?