- Game Programming Using Qt Beginner's Guide
- Witold Wysota Lorenz Haas
- 1104字
- 2025-04-04 20:19:16
Time for action – the logic of the dialog
Now, it is time to make our game settings dialog work. Earlier, we declared a signal-slot connection but now the slot itself needs to be implemented.
Open the form class generated by Creator. If you're still in the Design mode, you can quickly jump to the respective form class file using the Shift + F4 keyboard shortcut. Create a public slots section of the class and declare a void updateOKButtonState()
slot. Open the refactorization menu (Alt + Enter) and ask Creator to create the skeleton implementation of the slot for you. Fill the function body with the following code:
void ConfigurationDialog::updateOKButtonState() { bool pl1NameEmpty = ui->player1Name->text().isEmpty(); bool pl2NameEmpty = ui->player2Name->text().isEmpty(); QPushButton *okButton = ui->buttonBox->button(QDialogButtonBox::Ok); okButton->setDisabled(pl1NameEmpty || pl2NameEmpty); }
This code retrieves player names and checks whether either of them is empty. Then, it asks the button box that currently contains the OK and Cancel buttons to give a pointer to the button that accepts the dialog. Then, we set the button's disabled state based on whether both player names contain valid values or not. The button state also needs to be updated when we first create the dialog, so add invocation of updateOKButtonState()
to the constructor of the dialog:
ConfigurationDialog::ConfigurationDialog(QWidget *parent) :
QDialog(parent), ui(new Ui::ConfigurationDialog)
{
ui->setupUi(this);
updateOKButtonState();
}
The next thing to do is to allow to store and read player names from outside the dialog—since the ui
component is private, there is no access to it from outside the class code. This is a common situation and one that Qt is also compliant with. Each data field in almost every Qt class is private and may contain accessors (a getter and optionally a setter), which are public methods that allow to read and store values for data fields. Our dialog has two such fields—the names for the two players. At this point, we should note that they are good candidates for properties so at the end, we'll declare them as such. But first, let's start by implementing the accessors.
Setter methods in Qt are usually named using the lowercase pattern, for example, set
followed by the name of the property with the first letter converted to uppercase. In our situation, the two setters will be called setPlayer1Name
and setPlayer2Name
and they will both accept QString
and return void
. Declare them in the class header as shown in the following code snippet:
void setPlayer1Name(const QString &p1name); void setPlayer2Name(const QString &p2name);
Implement their bodies in the .cpp
file:
void ConfiguratiosDialog::setPlayer1Name(const QString &p1name) { ui->player1Name->setText(p1name); } void ConfigurationDialog::setPlayer2Name(const QString &p2name) { ui->player2Name->setText(p2name); }
Getter methods in Qt are usually called the same as the property that they are related to—player1Name
and player2Name
. Put the following code in the header file:
QString player1Name() const; QString player2Name() const;
Put the following code in the implementation file:
QString ConfigurationDialog::player1Name() const { return ui->player1Name->text(); } QString ConfigurationDialog::player2Name() const { return ui->player2Name->text(); }
The only thing left to do now is to declare the properties. Add the highlighted lines to the class declaration:
class ConfigurationDialog : public QDialog { Q_OBJECT Q_PROPERTY(QString player1Name READ player1Name WRITE setPlayer1Name) Q_PROPERTY(QString player2Name READ player2Name WRITE setPlayer2Name) public: ConfigurationDialog(QWidget *parent = 0);
Our dialog is now ready. You can test it by creating an instance of it in main()
and calling show()
or exec()
.
An application's main window
We already have two major components in our game—the game board and configuration dialog. Now, we will need to bind them together. To do this, we will use another important component—the QMainWindow
class. A "main window" represents the control center of an application. It can contain menus, toolbars, docking widgets, a status bar, and the actual widget content called a "central widget", as presented in the following diagram:

The central widget part doesn't need any extra explanation—it is a regular widget like any other. We will also not focus on dock widgets or the status bar here. They are useful components but they are so easy to master that you can learn about them yourself. Instead, we will spend some time mastering menus and toolbars. You have surely seen and used toolbars and menus in many applications and you know how important they are for good user experience.
The main hero shared by both these concepts is a class called QAction
, which represents a functionality that can be invoked by a user. A single action can have more than one incarnation—it can be an entry in a menu (the QMenu
instances), a toolbar (QToolBar
), button, or keyboard shortcut (QShortcut
). Manipulating the action (for example, changing its text) causes all its incarnations to update. For example, if you have a Save entry in the menu (with a keyboard shortcut bound to it), a Save icon in the toolbar, and maybe also a Save button somewhere else in your user interface and you want to disallow saving the document (for example, a map in your dungeons and dragons game level editor) because its contents haven't changed since the document was last loaded. In this case, if, the menu entry, toolbar icon, and button are all linked to the same QAction
instance then, once you set the enabled
property of the action to false
, all the three entities will become disabled as well. This is an easy way to keep different parts of your application in sync—if you disable an action object, you can be sure that all entries that trigger the functionality represented by the action are also disabled. Actions can be instantiated in code or created graphically using Action Editor in Qt Creator. An action can have different pieces of data associated with it—a text, tooltip, status bar tip, icons, and others that are less often used. All these are used by incarnations of your actions.
The Qt resource system
While speaking of icons, there is an important feature in Qt that you should learn. A natural way of creating icons is by loading images from the filesystem. The problem with this is that you have to install a bunch of files together with your application and you need to always know where they are located to be able to provide paths to access them. This is difficult but fortunately, Qt has a solution to this—it allows you to embed arbitrary files (such as images for icons) directly in the application that is executable. This is done by preparing resource files that are later compiled in the binary. Fortunately, Qt Creator provides a graphical tool for this as well.