Opening & Controlling Multiple Dialog Windows In A wxWidgets Project
One of the things that had bugged me forever in my years of using wxWidgets was not easily being able to open and control multiple Dialog windows. The idea behind what I had been trying to do (as had countless other thousands of people online) is quite simple; I wanted to open up a main Dialog window, with my main program buttons and gadgets on, but then I wanted to have a second window in the background that I could use to hold more gadgets, more controls. I also wanted a 3rd window that I would then set up as a debugging window; I could put data in there and hide it in my project unless you know the secret knock to get it to display 🙂 This would have saved me a lot of time and effort when I was coding my Litecoin Pool tools, instead of logging to a file and reading through it, I could have updated some gadgets in a seperate window and watched in real-time what the hell was going on with the data I was processing 🙂
So there-in lies the problem: When we open a new Dialog, it opens on top of the parent and now the parent is completely locked until the new window is closed. Very frustrating!
I tried a few different ways to achieve this in a way that worked for my project, and so far, this method is working the best for me. If theres a better way to do this, then please let me know in the comments below. I do like using the DialogBlocks tool to make my complex GUI’s as I find its just easier and more productive to do so. Im not too familiar with some of the editors, so i’m not sure if theres anything out there that is as good as DialogBlocks. It does miss some of the new classes that are available, but it works well for what I need it to.
When starting a new project (or in my case, I would make a new Main window in my existing projects) instead of creating a new wxDialog object, I created a new wxFrame. Frames look a little different to Dialogs, they inherit the Dark Grey background and there are no sizers. It’s also a fixed size (DialogBlocks). On this frame, I added some vertical sizers to start, and would construct my frame as normal. To remove the Dark Grey background, you can set a background colour, or use an ID panel etc. There’s quite a few different ways to design the interface properly, and everyone seems to have their own way of doing it 🙂
Now I want to add my Debugging window to my project. For this, I create a new wxDialog window called SecondaryWindow just as I normally would and construct it in exactly the same way. I can add some text strings, or a complete wxNotebook setup with some additional panels and gadgets as I need them. There really isn’t any limitations to what you can insert into the dialog. Once created, I have to initialize the windows manually. To help demonstrate this, I created a sample project which can be downloaded using 7zip download for your own reference. All future references to code, and this example, will be in relation to this sample (with the concept still working fine in your application).
DialogBlocks puts special comments around functions to help it identify which sections need to be automatically updated when changes are made in the Interface designer. Its a good idea, especially when (like me) I use both DialogBlocks and Visual Studio 2017 at the same time, so if I make changes in one, it auto reloads in the other and I know where the automated blocks begin & end.
Getting back to the topic at hand, the sample project contains two windows. The first window is our main window, which is built using a wxFrame. It has a text box, and six buttons. Three of the buttons control the showing/hiding of up to 3 small sample windows (whose class is called SecondaryWindow). Each window is separate, unique and can be controller independently. The other 3 buttons control the wxTextControl and insert text into one of the three windows. The windows can be shown/hidden at any time. All three of the created windows are derived from the same Dialog class, but there is nothing at all to stop you from creating completely independent and different window classes.
To create the three windows, at the bottom of the file mainwindow.h, in the class MainWindow function I have inserted these lines:
////@begin MainWindow member variables
wxTextCtrl* TextInputString;
////@end MainWindow member variables
// This is where we will initialize our 3 sample windows
SecondaryWindow *FirstWindow;
SecondaryWindow *SecondWindow;
SecondaryWindow *ThirdWindow;
// And create a variable to remember if the window is Visible or not
bool OpenedWindowA, OpenedWindowB, OpenedWindowC;
In the constructor code for the class, we set the values of the booleans to false so that the code thinks they are closed. By default in the project, I chose not to have them auto-open. At the bottom of the CreateControls() function, we can go ahead and initialize the windows themselves, along with giving each window a unique title to go with it:
wxButton* itemButton9 = new wxButton( itemStaticBoxSizer2->GetStaticBox(), ID_BUTTON_SHOWC, _("Show/Hide Window C"), wxDefaultPosition, wxDefaultSize, 0 );
itemBoxSizer4->Add(itemButton9, 1, wxALIGN_CENTER_VERTICAL|wxALL, 2);
////@end MainWindow content construction
// Now we should try to initialize the three extra windows so we can use them later.
MainWindow::FirstWindow = new SecondaryWindow(this);
MainWindow::SecondWindow = new SecondaryWindow(this);
MainWindow::ThirdWindow = new SecondaryWindow(this);
// Set some Window titles
MainWindow::FirstWindow->SetTitle(wxT("First Window"));
MainWindow::SecondWindow->SetTitle(wxT("Second Window"));
MainWindow::ThirdWindow->SetTitle(wxT("Third Window"));
Now that the windows are created, we can start to call them. For the purpose of the example project, I made buttons that show/hide each of the windows. To do this in DialogBlocks, I added the button and then created an Event to trigger each time the button was clicked. Going into that function, I removed the default comment lines that were inserted and replaced it with my own code like below:
void MainWindow::OnButtonShowAClick( wxCommandEvent& event )
{
if (MainWindow::OpenedWindowA == false) {
// Display the Window.
MainWindow::FirstWindow->Show();
MainWindow::OpenedWindowA = true;
}
else {
// Now we should Hide the window from view
MainWindow::FirstWindow->Hide();
MainWindow::OpenedWindowA = false;
}
// Skip the event
event.Skip();
}
Its a pretty crude method, but it works. As with any new Dialog, the window will appear by default in the centre of the parent, so you will have to move them around. The above code is modified for each window to produce the same effect. You can click the Show/Hide button to show/hide the window, or click the X button to close it. To make the contents of text appear in one of the windows, type something into the box and select the button for which window it should appear into.
Closing Notes
The sample project is pretty crude, and there are multiple ways to do it. The code is probably not the best in the world (I could pass the boolean directly to Show() for example and it will control hiding the window). You can also control opening the windows with ShowWithoutActivating() to display the window, but not switch the focus to it. Lot’s of different ways to do the same thing.
After spending a lot of time in the past working on trying to solve this for my own projects, I found a way that seems to work well for me, and I wanted to share it with the rest of the world who might be new to wxWidgets and are looking for that same answer. If you do find this example useful, please leave a friendly comment below.
Download The Sample Project
The sample project can be download from here: Link (1,354Kb)
Along with the source code & DialogBlocks project file to compile this project, there is also a compiled exe ready to run.
If you found this post, or the sample useful, please let me know in the comments below. Thank-you!
This entry was posted by FishGuy876 on August 26, 2019 at 10:35 am, and is filed under C / C++, Computers, wxWidgets. Follow any responses to this post through RSS 2.0. You can leave a response or trackback from your own site.
One comment
Leave a ReplyCancel reply
This site uses Akismet to reduce spam. Learn how your comment data is processed.
Quite Useful Post! Thanks for Sharing.