Game Programming using Qt 5 Beginner's Guide
上QQ阅读APP看书,第一时间看更新

Automatic slot connection and its drawbacks

Qt also offers an easier way to make a connection between signals of the form's elements and the slots of the class. You can right-click on the button in the central area of the form editor and select the Go to slot... option. You will be prompted to select one of the signals available in the button's class (QPushButton). After you select the clicked() signal, Qt Creator will automatically add a new on_startNewGame_clicked slot to our  MainWindow class.

The tricky part is that there is no connect() call that enforces the connection. How is the button's signal connected to this slot, then? The answer is Qt's automatic slot connection feature. When the constructor calls the ui->setupUi(this) function, it creates the widgets and other objects in the form and then calls the QMetaObject::connectSlotsByName method. This method looks at the list of slots existing in the widget class (in our case, MainWindow) and searches for ones that have their name in an on_<object name>_<signal name>
pattern, where <object name> is the objectName of an existing child widget and <signal name> is the name of one of this widget's signals. In our case, a button called startNewGame is a child widget of our widget, and it has a clicked signal, so this signal is automatically connected to an on_startNewGame_clicked slot.

While this is a really convenient feature, it has many drawbacks:

  • It makes your application harder to maintain. If you rename or remove the form element, you have to update or remove the slot manually. If you forget to do that, the application will only produce a warning at runtime when the automatic connection fails. In a large application, especially when not all forms are instantiated at the start of the application, there is a significant risk that you will miss the warning and the application will not work as intended.
  • You have to use a specific name for the slot (for example,  on_startNewGame_clicked() instead of a clean-looking startNewGame()).
  • Sometimes you want to connect signals from multiple objects to the same slot. Automatic slot connection doesn't provide a way to do this, and creating multiple slots just to call a single function will lead to unnecessary code bloat.
  • Automatic slot connection has a runtime cost, because it needs to examine the available children and slots and find the matching ones, but it's usually insignificant since it only runs when the form object is created.

The basic approach shown in the previous section is much more maintainable. Making an explicit connect() call with pointers to member functions will ensure that both signal and slot are specified properly. If you rename or remove the button, it will immediately result in a compilation error that is impossible to miss. You are also free to choose a meaningful name for the slot, so you can make it part of your public API, if desired.

Considering all this, we advise against using the automatic slot connection feature, as the convenience does not outweigh the drawbacks.