Have you ever felt that “creating a main window” in Qt is quick… until real life starts? The menu lives separately, toolbar buttons separately, the status bar is silent, and disabling one command requires changes in two places — and all this easily gets out of sync.
This chapter reveals how professional developers assemble the application “skeleton” so the interface doesn’t fall apart at the first extension. Here you’ll discover a non-obvious way to centralize commands, learn the secret of clean menu/toolbar synchronization, and gain development speed without code chaos.
We’ll examine 3 key QMainWindow components (central widget, toolbars, status bar), single source of truth via QAction, dock widgets (QDockWidget), and a “professional” splash screen (QSplashScreen) that masks lengthy initialization. Plus — practical comparison of SDI vs MDI and how to open multiple documents without turning your project into a tangle of signals.
If you need your application to look “real” — this is the transitional step you’d better not skip.
This chapter includes ready-to-use code examples.
Chapter Self-Check
Why is using QAction significantly more efficient than creating separate menu commands and toolbar buttons?Answer
Correct answer: QAction centralizes all interface elements (menu text, icon, keyboard shortcuts, tooltips) in a single object, eliminating code duplication and automatically synchronizing element states — for example, disabling an action immediately disables both the menu command and the toolbar button.
What’s the fundamental difference between QToolBar and QDockWidget widgets in terms of their purpose?Answer
Correct answer: QToolBar is designed for placing simple buttons for quick access to commands, while QDockWidget allows placing complex composite widgets that users can move between window sides and even detach into independent windows.
Why is it necessary to call QApplication::processEvents() during lengthy initialization operations?Answer
Correct answer: Without processing accumulated events, the interface will “freeze,” manifesting as a “not responding” application or spinning wait indicators. Calling processEvents() allows processing GUI events and maintaining interface responsiveness.
Why should the closeEvent() method in an SDI application check the document()->isModified() status before closing?Answer
Correct answer: This prevents loss of unsaved data — if the document is modified, the user is prompted to save changes. Calling pe->ignore() allows canceling the window closure if the user changes their mind.
What problem will arise if you call m_pma->activeSubWindow()->widget() in an MDI application without prior checking?Answer
Correct answer: If there’s no active window in the workspace, activeSubWindow() will return nullptr, and attempting to call widget() will lead to a program crash. You must first check the result for nullptr.
What’s the advantage of using setAttribute(Qt::WA_DeleteOnClose) for document windows in MDI applications?Answer
Correct answer: The attribute guarantees automatic widget deletion from memory when the window closes, preventing memory leaks when working with multiple documents without the need for manual object lifetime management.
Why must the Windows menu in an MDI application be cleared and refilled before each display?Answer
Correct answer: The composition of open documents changes dynamically — windows are created and closed. Recreating the menu before display ensures the document list is current and the checkmark is correctly set for the active window.
What is the QSignalMapper object used for in the context of an MDI application’s Windows menu?Answer
Correct answer: QSignalMapper allows sending a pointer to a specific document window along with the signal, since the standard triggered() signal only passes a boolean value. This is necessary for activating the selected window.
How does the setAllowedAreas() method in QDockWidget affect the user experience of working with the application?Answer
Correct answer: The method restricts possible dock placement locations, allowing the developer to control interface layout — for example, prohibiting panel placement on the sides if it’s too wide for vertical positioning.
What’s the difference between temporary and permanent status bar messages from an application architecture perspective?Answer
Correct answer: Temporary messages (showMessage) use a shared text area and automatically clear, while permanent messages (addPermanentWidget) require separate widgets and remain visible permanently — this separates temporary notifications from stable status information.
What will happen if you don’t connect the document’s changeWindowTitle() signal to the main window’s slot in an MDI application?Answer
Correct answer: The document window title won’t update when saving a file under a new name or loading a file — the user will see outdated information, reducing application usability.
Why is the QSplashScreen object created after QApplication but before calling exec() in the splash screen example?Answer
Correct answer: QApplication must exist for GUI operations, and the splash screen must be displayed before starting the event processing loop exec() — to be visible during application initialization and hide loading time.
What architectural problem does delegating load and save operations from MDIProgram to DocWindow solve?Answer
Correct answer: Separation of responsibilities — MDIProgram manages windows and menus, while DocWindow encapsulates file handling logic. This adheres to the single responsibility principle and simplifies DocWindow reuse in other applications.
Practice Assignments
Easy Level
Text Editor with Toolbar
Create an SDI application with a text editor (QTextEdit) that has a toolbar with three buttons: Bold, Italic, and Underline. Use QAction for each button and add corresponding icons. The buttons should change the formatting of selected text.
Hints: Inherit the class from QMainWindow. Use QTextEdit::setFontWeight(), setFontItalic(), and setFontUnderline() to change formatting. Create QAction objects with setText(), setIcon(), and setToolTip() methods. Connect each action’s triggered() signal to slots that modify formatting. Add actions to the toolbar using the addAction() method.
Medium Level
Application with Customizable Docks
Develop an application with a central widget (QTextEdit) and two dock widgets: one for displaying a list of open files (QListWidget), the second for document properties (character count, lines, words in QLabel). Docks should be placed left and right, but users can move them. When entering text, information in the right dock should update in real-time.
Hints: Create two QDockWidget instances and set appropriate widgets using setWidget(). Use addDockWidget() with Qt::LeftDockWidgetArea and Qt::RightDockWidgetArea parameters. Connect the text editor’s textChanged() signal to a slot that recalculates statistics. Use QString::length(), split(‘\n’).size(), and split(QRegularExpression(“\\s+”)).size() to count characters, lines, and words.
Hard Level
Full-Featured MDI Application with Unsaved Changes Handling
Implement an MDI application for working with text documents that supports creating, opening, and saving files. The application should: track unsaved changes in each document (display asterisk in title), warn when closing a window with unsaved data, correctly handle closing the entire application with checking all open documents, implement a Windows menu with Cascade and Tile commands, as well as a list of all open documents with the ability to switch between them.
Hints: Inherit the document class from QTextEdit and add change tracking via document()->setModified(). Override closeEvent() in both the document window and the main window. In the main window’s closeEvent(), use a loop over m_pma->subWindowList() to check isModified() for all documents. Use QMessageBox::question() with Save/Discard/Cancel buttons. Update the window title by adding “[*]” and calling setWindowModified(true). In the Windows menu, use a loop to create actions with document names and setCheckable(true) for the active window.
💬 Join the Discussion!
Got a handle on MDI application architecture? Have questions about when to use QDockWidget instead of a toolbar?
Having difficulties handling unsaved changes or synchronizing the interface via QAction?
Share your experience implementing main application windows, discuss best practices for working with documents, or ask questions to the community!