C++ MFC Attach different dialogs for each tab in CTabCtrl - c++

I have a small project I'm working on. It has multiple dialogs so what I want to do is to have 1 main Window with multiple tabs in it. I want each tab to represent different dialog. For now I have that : Dialog with CTabCtrl opens as I expect and I have 3 tabs attached to it, when I press (for example) tab 1 it creates a new Modeless instance of my wanted PopUpDialog and it appears right where I want it. All good. But then if I move my main window , my PopUpDialog (which is borderless) stays on the same spot where he pops up at the start. Seems like the "spawn" location of my dialog is mapped to my CTabCtrl Dialog but it's not attached to it. I think I need to make it a child class or something like this . I am new to MFC and programming. I've been looking for answers for past 2 days but many links were deleted because they're too old. This is a little code example of what I'm doing:
void CTabCtrlDialog::OnSelchangeTab(NMHDR *pNMHDR, LRESULT *pResult)
{
CDialogIwantToPopUp *m_Page;
m_Page = new CDialogIwantToPopUp();
m_Page->Create(IDD_POPUP_DIALOG, m_tabTest.GetWindow(IDD_POPUP_DIALOG));
m_Page->ShowWindow(SW_SHOW);
}
This is a function (in my dialog that contains the tab control) that is responsible for click on any tab event.

I find it easiest to use a property sheet in this situation, but if that isn't appropriate for you, you need to ensure each page has the DS_CHILD style (Style: Child in the resource editor property list).
When creating the page, its parent window should be 'this' rather than what you're doing with GetWindow().

Related

MFC dialog-based app with tab control - Visual Studio bugs/restrictions make recommended path impossible?

Create a dialog-based application in Visual Studio 2019. Insert a new dialog in the resources. Place a control (or two) on that dialog that you will later (try to) hook up to a variable (e.g. an edit box to enter your name).
Prepare to add that control variable by creating a class for this second dialog. If you inherit from CDialogEx (or perhaps other classes too - not tested), you can go on to add a variable for the control you added - easy, normal.
But if you had the "tab control" context from the title above in your mind, and chose to inherit from CMFCPropertyPage instead, can you add a variable subsequently? No you cannot - the class added makes no reference to the ID of the dialog resource, and so the Add Variable process has no basis to find a class to add the variable to.
I think this is a bug in Visual Studio... but I'm not 100% sure because I have always found the documentation around property sheets and property pages somewhat confusing. Specifically:
Do the classes implementing the tabs contents on a tab control "contain" the controls "on" the tab... or is the tab control really just a way to provide visual cues to show/hide sets of controls, and all of those controls and associated variables reside in one class?
I believe it's intended to be the former, but I can imagine that one uses a tab control because there are strong similarities between tab contents, and therefore potential benefits in implementing all the control variables in one place so as to avoid duplication. I just wish it was stated explicitly somewhere what the intention was.
Wider context: I'm trying to implement a dialog-based app with a tab control dominating that dialog. MS documentation says to implement a tab control using CPropertySheet and CPropertyPage to implement the tabbed dialog and tab contents. However, there is no (direct) way to create a dialog-based application whose main dialog inherits from CPropertySheet. When you look for examples of tab controls at the application level, you readily find things that deviate from the documented path considerably - using neither CPropertySheet nor CPropertyPage and using the WM_LBUTTONDOWN event instead of TCN_SELCHANGE, both without obvious reasons.
Any tips on (a) how to repair the apparent Visual Studio bug and/or (b) how to inherit from CPropertySheet for my application dialog and/or (c) where to find a clearer and more conventional example of tab control use at the top level would be greatly appreciated.
Given that there appears to be no clear and consistent way of approaching this, if (like me) you think "how hard can it be?", you might naively set out to see if you can create a new dialog-based application based on CDialog and manually convert it to CPropertyPage. You might fare better; I quickly hit a weird problem with the app compiling but not running - it could not load the window caption from the resource ID, despite the caption literally being there in black and white. Due to the weirdness, this was a red flag, and so to my mind problem (b) seems to be not worth the effort.
Without a CPropertySheet at the top level, there is no point having any kind of CPropertyPage or CMFCPropertyPage involved, making problem (a) pointless. That said, if you manually convert from (default) CDialogEx to CPropertyPage for your tab classes, it seems to have no problem compiling and running - the tabs just don't have any functionality that integrates with the main dialog.
Instead, I can now recommend working through the details of the video example even though it does strange things at first glance. You can achieve the desired result in more or less the same way as follows:
Use plain CDialogEx throughout, and so provide all the tab switching/showing/hiding/control work yourself (which the example demonstrates).
Create your main dialog and all tabs in the resource editor, adding the CDialog-based classes from there.
If you create your tab dialog resources via Insert Dialog (generic) instead of Add Resource (uses specific templates) then you will have to manually set certain dialog properties for each tab:
Border: Thin (or I preferred None)
Style: Child
System Menu: false
Title Bar: false
You can simplify the repositioning of the tabs (see below; it barely justifies the separate SetRectangle() function)
You should (probably) drive the tab changing from the TCN_SELCHANGE event instead of WM_LBUTTONDOWN
As noted, repositioning the tabs can be simplified to something like:
CRect tabRect;
m_tabControl.GetWindowRect( &tabRect );
for ( int i = 0; i < m_totalTabs; i++ )
{
m_pTabPage[ i ]->SetWindowPos( &wndTop, tabRect.left, tabRect.top, 0, 0,
i == m_currentTab? SWP_NOSIZE|SWP_SHOWWINDOW : SWP_NOSIZE|SWP_HIDEWINDOW );
}
Additional calls to ShowWindow() for each tab shown in the example are redundant.
One time, I had made on application as such. I don't remember if I used the Visual Studio new project wizard. Most probably, I did. But I will assist you on how to do it if you can not reach how to do it via the assistant.
The essential things:
Define the main dialog in the resources and the respective class in its H and CPP files.
In the YourAppClass::InitInstance you will need to have something like:
YourMainDlgClass dlg;
m_pMainWnd = &dlg;
INT_PTR nResponse = dlg.DoModal();
if (nResponse == IDOK)
{
// TODO: Place code here to handle when the dialog is
// dismissed with OK
}
else if (nResponse == IDCANCEL)
{
// TODO: Place code here to handle when the dialog is
// dismissed with Cancel
}
else if (nResponse == -1)
{
TRACE(traceAppMsg, 0, "Warning: dialog creation failed, so application is terminating unexpectedly.\n");
TRACE(traceAppMsg, 0, "Warning: if you are using MFC controls on the dialog, you cannot #define _AFX_NO_MFC_CONTROLS_IN_DIALOGS.\n");
}
Insert a CMFCTabCtrl element in your dialog for tabs, instead of using a CPropertySheet.

MFC: Use a dialog's class for a second dialog

I have an dialog with several buttons and sliders on it and am adding another button that should close the dialog and open another that is essentially a mini version it.
I need access to the buttons in the first dialog in the second mini dialog (since they should have the same functionality).
Is there a way to use the class from the first dialog on the second so that I have access to those buttons? I've tried right clicking the dialog and adding a class, but it makes me make a new one instead of being able to use an existing one.
Thanks in advance!

Display and use the same MFC CList control in multiple dialogs

I am coding a test application for a windows CE device. This is the first time I am programming for a handheld device. I use MFC VC++ on Visual Studio 2008. I have found that there are many restrictions in the controls and what I could do with them when running the program on a handy versus when I run a similar program on a desktop computer.
Now, the device I am currently deploying my test program to, does not have a touchscreen and has few extra keys other that the numberpad 0-9 keys. So, I have to do with a simple GUI that uses keydowns to call specific functions like add, edit, delete etc... It also forces me to use separate dialogs for each of these functions so as to avoid unnecessary mouse cursor usage.
This leads me to my current problem: The 'ADD' dialog of my test app adds some user data to a CListCtrl that is on the 'MAIN' dialog. The 'EDIT/DELETE' dialog is to allow the user to select the desired data from its own CListCtrl and press the "ENTER" key, which thereby deletes the selected data from the 'MAIN' dialog's CListCtrl. Thus, both the main dialog and the 'EDIT/DELETE' dialog have CListCtrl with the exact same data. So, instead of having to use 2 separate list controls and using loops to copy the data to and fro among them, is there a way in which i could use the exact same CListCtrl (one and only one instance of the CListCtrl exists), but display it on 2 separate dialogs? This would remove all the copying code, as well as halve the amount of data in memory.
I tried passing a pointer to the MAIN dialog's CListCtrl to the 'EDIT/DELETE' dialog in hopes that I could redraw the control there, but in vain. I could call the RedrawWindow, RedrawItems commands, but they seem to have no effect in the 'EDIT/DELETE' dialog (I think it is because the control itself is not present on the edit/delete dialog). Any other suggestions?
You could temporarily change the parent of the ListCtrl using CWnd::SetParent to the EDIT/DELETE dialog, and set the position with CWnd::SetWindowPos to where you want to have it. When the dialog gets closed, set the parent back to the MAIN dialog.

Embedding dialogs in main dialog and switching them with button click in MFC

I have a design like below:
So basically, I want to embed three dialogs in the application main dialog and switch between them, for each button click i.e., button 1 will show dialog one , button 2 will hide dialog 1 and show dialog 2 .. and so on.
Each dialog will be having a different design and functions.
I tried using CPropertySheet class to Add pages but its GUI is different. It has either option for navigating the dialogs using next / back button , or from a tab control.
None of which is as per my requirement.
So I want to know is it possible to have a design like this in MFC ? If yes how? Which Class/ control should I use.
Any help will be appreciated.
What you can do is use a normal CDialog class, add your buttons to it and also create a frame/rect as a placeholder for where your embedded dialogs are to appear. The following piece of code will create and position your embedded dialog.
CRect rect;
CWnd *pHost = GetDlgItem(ID_OF_YOUR_FRAME_RECT);
pHost->GetWindowRect(&rect);
ScreenToClient(&rect);
pDialog->Create(ID_OF_YOUR_DIALOG, this);
pDialog->MoveWindow(&rect);
pDialog->ShowWindow(SW_SHOW);
On button clicks, you hide the previously shown dialog (SW_HIDE) and show your selected dialog(SW_SHOW) with ShowWindow(...).
If you create your embedded dialogs with IDD_FORMVIEW style in the add resource editor it'll have the proper styles for embedding.
Another option is probably to use an embedded PropertySheet and hide the tab row and programatically change the tabs on the button clicks. I just find it to be too much fuzz with borders, positioning, validation and such for my liking.
If you have the MFC Feature Pack, that first came with VS2008 SP1 and is in all later versions, you might like to consider CMFCPropertySheet. There are a number of examples on the linked page, that are very similar to your design.
For example, this:
What worked for me just using dialog based application is SetParent() method. Dont know why nobody mentioned it. It seems to work fine.
I am doing like below:
VERIFY(pDlg1.Create(PanelDlg::IDD, this));
VERIFY(pDlg2.Create(PanelDlg2::IDD, this));
VERIFY(pDlg3.Create(PanelDlg2::IDD, this));
::SetParent(pDlg1.GetSafeHwnd(), this->m_hWnd);
::SetParent(pDlg2.GetSafeHwnd(), this->m_hWnd);
::SetParent(pDlg3.GetSafeHwnd(), this->m_hWnd);
Now I can show or hide a child dialog at will (button clicks) as below:
pDlg1.ShowWindow(SW_SHOW);
pDlg2.ShowWindow(SW_HIDE);
pDlg3.ShowWindow(SW_HIDE);

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.