Qt Private Slot Example

 admin

©2016 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. This private slot is used to move the shot while it is in the air, using a QTimer. Private: void paintShot( QPainter. ); This private function paints the shot. QRect shotRect const; This private function returns the shot's enclosing rectangle if one is in the air; otherwise the returned rectangle is undefined. Slots and signals must have same parameters. Otherwise, the connection will not occur. Not only for connection, slot function must have same parameters with signal. For example, this sample doesn’t work: QObject::connect(ui.comboBox, SIGNAL (activated(int)), this, SLOT (onComboboxActivated)); But it works.

Nearly all of the code for the Application example is in the MainWindow class, which inherits QMainWindow. QMainWindow provides the framework for windows that have menus, toolbars, dock windows, and a status bar. The application provides File, Edit, and Help entries in the menu bar, with the following popup menus:

The status bar at the bottom of the main window shows a description of the menu item or toolbar button under the cursor.

We ensure that the application responds to user input by connecting most of the editor's input widgets (including the system tray icon) to the application's private slots. But note the visibility checkbox; its toggled signal is connected to the icon 's setVisible function instead. Slots are funct ions defined as slot like this example: private slots: void onButtonClicked; this code on header file. And last important think is that, signals and slots must have same parameters. It works: QObject::connect(ui.comboBox, SIGNAL(activated(int)), this, SLOT(onComboboxActivated(int))).

Qt Private Slot Example

To keep the example simple, recently opened files aren't shown in the File menu, even though this feature is desired in 90% of applications. Furthermore, this example can only load one file at a time. The SDI and MDI examples show how to lift these restrictions and how to implement recently opened files handling.

MainWindow Class Definition

Here's the class definition:

The public API is restricted to the constructor. In the protected section, we reimplement QWidget::closeEvent() to detect when the user attempts to close the window, and warn the user about unsaved changes. In the private slots section, we declare slots that correspond to menu entries, as well as a mysterious documentWasModified() slot. Finally, in the private section of the class, we have various members that will be explained in due time.

MainWindow Class Implementation

We start by including <QtWidgets>, a header file that contains the definition of all classes in the Qt Core, Qt GUI and Qt Widgets modules. This saves us from the trouble of having to include every class individually. We also include mainwindow.h.

You might wonder why we don't include <QtWidgets> in mainwindow.h and be done with it. The reason is that including such a large header from another header file can rapidly degrade performances. Here, it wouldn't do any harm, but it's still generally a good idea to include only the header files that are strictly necessary from another header file.

In the constructor, we start by creating a QPlainTextEdit widget as a child of the main window (the this object). Then we call QMainWindow::setCentralWidget() to tell that this is going to be the widget that occupies the central area of the main window, between the toolbars and the status bar.

Then we call createActions() and createStatusBar(), two private functions that set up the user interface. After that, we call readSettings() to restore the user's preferences.

We establish a signal-slot connection between the QPlainTextEdit's document object and our documentWasModified() slot. Whenever the user modifies the text in the QPlainTextEdit, we want to update the title bar to show that the file was modified.

At the end, we set the window title using the private setCurrentFile() function. We'll come back to this later.

When the user attempts to close the window, we call the private function maybeSave() to give the user the possibility to save pending changes. The function returns true if the user wants the application to close; otherwise, it returns false. In the first case, we save the user's preferences to disk and accept the close event; in the second case, we ignore the close event, meaning that the application will stay up and running as if nothing happened.

The newFile() slot is invoked when the user selects File New from the menu. We call maybeSave() to save any pending changes and if the user accepts to go on, we clear the QPlainTextEdit and call the private function setCurrentFile() to update the window title and clear the windowModified flag.

The open() slot is invoked when the user clicks File Open. We pop up a QFileDialog asking the user to choose a file. If the user chooses a file (i.e., fileName is not an empty string), we call the private function loadFile() to actually load the file.

The save() slot is invoked when the user clicks File Save. If the user hasn't provided a name for the file yet, we call saveAs(); otherwise, we call the private function saveFile() to actually save the file.

In saveAs(), we start by popping up a QFileDialog asking the user to provide a name. If the user clicks Cancel, the returned file name is empty, and we do nothing.

The application's About box is done using one statement, using the QMessageBox::about() static function and relying on its support for an HTML subset.

The tr() call around the literal string marks the string for translation. It is a good habit to call tr() on all user-visible strings, in case you later decide to translate your application to other languages. The Internationalization with Qt overview covers tr() in more detail.

The documentWasModified() slot is invoked each time the text in the QPlainTextEdit changes because of user edits. We call QWidget::setWindowModified() to make the title bar show that the file was modified. How this is done varies on each platform.

The createActions() private function, which is called from the MainWindow constructor, creates QActions and populates the menus and two toolbars. The code is very repetitive, so we show only the actions corresponding to File New, File Open, and Help About Qt.

A QAction is an object that represents one user action, such as saving a file or invoking a dialog. An action can be put in a QMenu or a QToolBar, or both, or in any other widget that reimplements QWidget::actionEvent().

An action has a text that is shown in the menu, an icon, a shortcut key, a tooltip, a status tip (shown in the status bar), a 'What's This?' text, and more. It emits a triggered() signal whenever the user invokes the action (e.g., by clicking the associated menu item or toolbar button).

Instances of QAction can be created by passing a parent QObject or by using one of the convenience functions of QMenu, QMenuBar or QToolBar. We create the actions that are in a menu as well as in a toolbar parented on the window to prevent ownership issues. For actions that are only in the menu, we use the convenience function QMenu::addAction(), which allows us to pass text, icon and the target object and its slot member function.

Creating toolbars is very similar to creating menus. The same actions that we put in the menus can be reused in the toolbars. After creating the action, we add it to the toolbar using QToolBar::addAction().

The code above contains one more idiom that must be explained. For some of the actions, we specify an icon as a QIcon to the QAction constructor. We use QIcon::fromTheme() to obtain the correct standard icon from the underlying window system. If that fails due to the platform not supporting it, we pass a file name as fallback. Here, the file name starts with :. Such file names aren't ordinary file names, but rather path in the executable's stored resources. We'll come back to this when we review the application.qrc file that's part of the project.

The Edit Cut and Edit Copy actions must be available only when the QPlainTextEdit contains selected text. We disable them by default and connect the QPlainTextEdit::copyAvailable() signal to the QAction::setEnabled() slot, ensuring that the actions are disabled when the text editor has no selection.

Just before we create the Help menu, we call QMenuBar::addSeparator(). This has no effect for most widget styles (e.g., Windows and macOS styles), but for some styles this makes sure that Help is pushed to the right side of the menu bar.

QMainWindow::statusBar() returns a pointer to the main window's QStatusBar widget. Like with QMainWindow::menuBar(), the widget is automatically created the first time the function is called.

The readSettings() function is called from the constructor to load the user's preferences and other application settings. The QSettings class provides a high-level interface for storing settings permanently on disk. On Windows, it uses the (in)famous Windows registry; on macOS, it uses the native XML-based CFPreferences API; on Unix/X11, it uses text files.

The QSettings constructor takes arguments that identify your company and the name of the product. This ensures that the settings for different applications are kept separately.

We use QSettings::value() to extract the value of the geometry setting. The second argument to QSettings::value() is optional and specifies a default value for the setting if there exists none. This value is used the first time the application is run.

We use QWidget::saveGeometry() and Widget::restoreGeometry() to save the position. They use an opaque QByteArray to store screen number, geometry and window state.

The writeSettings() function is called from closeEvent(). Writing settings is similar to reading them, except simpler. The arguments to the QSettings constructor must be the same as in readSettings().

The maybeSave() function is called to save pending changes. If there are pending changes, it pops up a QMessageBox giving the user to save the document. The options are QMessageBox::Yes, QMessageBox::No, and QMessageBox::Cancel. The Yes button is made the default button (the button that is invoked when the user presses Return) using the QMessageBox::Default flag; the Cancel button is made the escape button (the button that is invoked when the user presses Esc) using the QMessageBox::Escape flag.

The maybeSave() function returns true in all cases, except when the user clicks Cancel or saving the file fails. The caller must check the return value and stop whatever it was doing if the return value is false.

In loadFile(), we use QFile and QTextStream to read in the data. The QFile object provides access to the bytes stored in a file.

We start by opening the file in read-only mode. The QFile::Text flag indicates that the file is a text file, not a binary file. On Unix and macOS, this makes no difference, but on Windows, it ensures that the 'rn' end-of-line sequence is converted to 'n' when reading.

If we successfully opened the file, we use a QTextStream object to read in the data. QTextStream automatically converts the 8-bit data into a Unicode QString and supports various encodings. If no encoding is specified, QTextStream assumes the file is written using the system's default 8-bit encoding (for example, Latin-1; see QTextCodec::codecForLocale() for details).

Since the call to QTextStream::readAll() might take some time, we set the cursor to be Qt::WaitCursor for the entire application while it goes on.

At the end, we call the private setCurrentFile() function, which we'll cover in a moment, and we display the string 'File loaded' in the status bar for 2 seconds (2000 milliseconds).

Saving a file is very similar to loading one. Here, the QFile::Text flag ensures that on Windows, 'n' is converted into 'rn' to conform to the Windows convension.

The setCurrentFile() function is called to reset the state of a few variables when a file is loaded or saved, or when the user starts editing a new file (in which case fileName is empty). We update the curFile variable, clear the QTextDocument::modified flag and the associated QWidget:windowModified flag, and update the window title to contain the new file name (or untitled.txt).

The strippedName() function call around curFile in the QWidget::setWindowTitle() call shortens the file name to exclude the path. Here's the function:

Qt Private Slot Example For Real

The main() Function

The main() function for this application is typical of applications that contain one main window:

The main function uses QCommandLineParser to check whether some file argument was passed to the application and loads it via MainWindow::loadFile().

The Resource File

As you will probably recall, for some of the actions, we specified icons with file names starting with : and mentioned that such file names aren't ordinary file names, but path in the executable's stored resources. These resources are compiled

The resources associated with an application are specified in a .qrc file, an XML-based file format that lists files on the disk. Here's the application.qrc file that's used by the Application example:

The .png files listed in the application.qrc file are files that are part of the Application example's source tree. Paths are relative to the directory where the application.qrc file is located (the mainwindows/application directory).

The resource file must be mentioned in the application.pro file so that qmake knows about it:

qmake will produce make rules to generate a file called qrc_application.cpp that is linked into the application. This file contains all the data for the images and other resources as static C++ arrays of compressed binary data. See The Qt Resource System for more information about resources.

Files:

Images:

Signals and slots are used for communication between objects. The signals and slots mechanism is a central feature of Qt and probably the part that differs most from the features provided by other frameworks.

Introduction

In GUI programming, when we change one widget, we often want another widget to be notified. More generally, we want objects of any kind to be able to communicate with one another. For example, if a user clicks a Close button, we probably want the window's close() function to be called.

Older toolkits achieve this kind of communication using callbacks. A callback is a pointer to a function, so if you want a processing function to notify you about some event you pass a pointer to another function (the callback) to the processing function. The processing function then calls the callback when appropriate. Callbacks have two fundamental flaws: Firstly, they are not type-safe. We can never be certain that the processing function will call the callback with the correct arguments. Secondly, the callback is strongly coupled to the processing function since the processing function must know which callback to call.

Signals and Slots

In Qt, we have an alternative to the callback technique: We use signals and slots. A signal is emitted when a particular event occurs. Qt's widgets have many predefined signals, but we can always subclass widgets to add our own signals to them. A slot is a function that is called in response to a particular signal. Qt's widgets have many pre-defined slots, but it is common practice to subclass widgets and add your own slots so that you can handle the signals that you are interested in.

The signals and slots mechanism is type safe: The signature of a signal must match the signature of the receiving slot. (In fact a slot may have a shorter signature than the signal it receives because it can ignore extra arguments.) Since the signatures are compatible, the compiler can help us detect type mismatches. Signals and slots are loosely coupled: A class which emits a signal neither knows nor cares which slots receive the signal. Qt's signals and slots mechanism ensures that if you connect a signal to a slot, the slot will be called with the signal's parameters at the right time. Signals and slots can take any number of arguments of any type. They are completely type safe.

All classes that inherit from QObject or one of its subclasses (e.g., QWidget) can contain signals and slots. Signals are emitted by objects when they change their state in a way that may be interesting to other objects. This is all the object does to communicate. It does not know or care whether anything is receiving the signals it emits. This is true information encapsulation, and ensures that the object can be used as a software component.

Slots can be used for receiving signals, but they are also normal member functions. Just as an object does not know if anything receives its signals, a slot does not know if it has any signals connected to it. This ensures that truly independent components can be created with Qt.

You can connect as many signals as you want to a single slot, and a signal can be connected to as many slots as you need. It is even possible to connect a signal directly to another signal. (This will emit the second signal immediately whenever the first is emitted.)

Together, signals and slots make up a powerful component programming mechanism.

A Small Example

A minimal C++ class declaration might read:

A small QObject-based class might read:

The QObject-based version has the same internal state, and provides public methods to access the state, but in addition it has support for component programming using signals and slots. This class can tell the outside world that its state has changed by emitting a signal, valueChanged(), and it has a slot which other objects can send signals to.

Private

All classes that contain signals or slots must mention Q_OBJECT at the top of their declaration. They must also derive (directly or indirectly) from QObject.

Slots are implemented by the application programmer. Here is a possible implementation of the Counter::setValue() slot:

The emit line emits the signal valueChanged() from the object, with the new value as argument.

In the following code snippet, we create two Counter objects and connect the first object's valueChanged() signal to the second object's setValue() slot using QObject::connect():

Calling a.setValue(12) makes a emit a valueChanged(12) signal, which b will receive in its setValue() slot, i.e. b.setValue(12) is called. Then b emits the same valueChanged() signal, but since no slot has been connected to b's valueChanged() signal, the signal is ignored.

Note that the setValue() function sets the value and emits the signal only if value != m_value. This prevents infinite looping in the case of cyclic connections (e.g., if b.valueChanged() were connected to a.setValue()).

By default, for every connection you make, a signal is emitted; two signals are emitted for duplicate connections. You can break all of these connections with a single disconnect() call. If you pass the Qt::UniqueConnectiontype, the connection will only be made if it is not a duplicate. If there is already a duplicate (exact same signal to the exact same slot on the same objects), the connection will fail and connect will return false

This example illustrates that objects can work together without needing to know any information about each other. To enable this, the objects only need to be connected together, and this can be achieved with some simple QObject::connect() function calls, or with uic's automatic connections feature.

Building the Example

The C++ preprocessor changes or removes the signals, slots, and emit keywords so that the compiler is presented with standard C++.

By running the moc on class definitions that contain signals or slots, a C++ source file is produced which should be compiled and linked with the other object files for the application. If you use qmake, the makefile rules to automatically invoke moc will be added to your project's makefile.

Signals

Signals are emitted by an object when its internal state has changed in some way that might be interesting to the object's client or owner. Only the class that defines a signal and its subclasses can emit the signal.

When a signal is emitted, the slots connected to it are usually executed immediately, just like a normal function call. When this happens, the signals and slots mechanism is totally independent of any GUI event loop. Execution of the code following the emit statement will occur once all slots have returned. The situation is slightly different when using queued connections; in such a case, the code following the emit keyword will continue immediately, and the slots will be executed later.

If several slots are connected to one signal, the slots will be executed one after the other, in the order they have been connected, when the signal is emitted.

Signals are automatically generated by the moc and must not be implemented in the .cpp file. They can never have return types (i.e. use void).

A note about arguments: Our experience shows that signals and slots are more reusable if they do not use special types. If QScrollBar::valueChanged() were to use a special type such as the hypothetical QScrollBar::Range, it could only be connected to slots designed specifically for QScrollBar. Connecting different input widgets together would be impossible.

Slots

A slot is called when a signal connected to it is emitted. Slots are normal C++ functions and can be called normally; their only special feature is that signals can be connected to them.

Since slots are normal member functions, they follow the normal C++ rules when called directly. However, as slots, they can be invoked by any component, regardless of its access level, via a signal-slot connection. This means that a signal emitted from an instance of an arbitrary class can cause a private slot to be invoked in an instance of an unrelated class.

You can also define slots to be virtual, which we have found quite useful in practice.

Compared to callbacks, signals and slots are slightly slower because of the increased flexibility they provide, although the difference for real applications is insignificant. In general, emitting a signal that is connected to some slots, is approximately ten times slower than calling the receivers directly, with non-virtual function calls. This is the overhead required to locate the connection object, to safely iterate over all connections (i.e. checking that subsequent receivers have not been destroyed during the emission), and to marshall any parameters in a generic fashion. While ten non-virtual function calls may sound like a lot, it's much less overhead than any new or delete operation, for example. As soon as you perform a string, vector or list operation that behind the scene requires new or delete, the signals and slots overhead is only responsible for a very small proportion of the complete function call costs.

The same is true whenever you do a system call in a slot; or indirectly call more than ten functions. On an i586-500, you can emit around 2,000,000 signals per second connected to one receiver, or around 1,200,000 per second connected to two receivers. The simplicity and flexibility of the signals and slots mechanism is well worth the overhead, which your users won't even notice.

Note that other libraries that define variables called signals or slots may cause compiler warnings and errors when compiled alongside a Qt-based application. To solve this problem, #undef the offending preprocessor symbol.

Meta-Object Information

The meta-object compiler (moc) parses the class declaration in a C++ file and generates C++ code that initializes the meta-object. The meta-object contains the names of all the signal and slot members, as well as pointers to these functions.

The meta-object contains additional information such as the object's class name. You can also check if an object inherits a specific class, for example:

The meta-object information is also used by qobject_cast<T>(), which is similar to QObject::inherits() but is less error-prone:

See Meta-Object System for more information.

A Real Example

Here is a simple commented example of a widget.

LcdNumber inherits QObject, which has most of the signal-slot knowledge, via QFrame and QWidget. It is somewhat similar to the built-in QLCDNumber widget.

The Q_OBJECT macro is expanded by the preprocessor to declare several member functions that are implemented by the moc; if you get compiler errors along the lines of 'undefined reference to vtable for LcdNumber', you have probably forgotten to run the moc or to include the moc output in the link command.

It's not obviously relevant to the moc, but if you inherit QWidget you almost certainly want to have the parent argument in your constructor and pass it to the base class's constructor.

Some destructors and member functions are omitted here; the moc ignores member functions.

LcdNumber emits a signal when it is asked to show an impossible value.

If you don't care about overflow, or you know that overflow cannot occur, you can ignore the overflow() signal, i.e. don't connect it to any slot.

If on the other hand you want to call two different error functions when the number overflows, simply connect the signal to two different slots. Qt will call both (in the order they were connected).

A slot is a receiving function used to get information about state changes in other widgets. LcdNumber uses it, as the code above indicates, to set the displayed number. Since display() is part of the class's interface with the rest of the program, the slot is public.

Several of the example programs connect the valueChanged() signal of a QScrollBar to the display() slot, so the LCD number continuously shows the value of the scroll bar.

Note that display() is overloaded; Qt will select the appropriate version when you connect a signal to the slot. With callbacks, you'd have to find five different names and keep track of the types yourself.

Some irrelevant member functions have been omitted from this example.

Signals And Slots With Default Arguments

The signatures of signals and slots may contain arguments, and the arguments can have default values. Consider QObject::destroyed():

When a QObject is deleted, it emits this QObject::destroyed() signal. We want to catch this signal, wherever we might have a dangling reference to the deleted QObject, so we can clean it up. A suitable slot signature might be:

To connect the signal to the slot, we use QObject::connect() and the SIGNAL() and SLOT() macros. The rule about whether to include arguments or not in the SIGNAL() and SLOT() macros, if the arguments have default values, is that the signature passed to the SIGNAL() macro must not have fewer arguments than the signature passed to the SLOT() macro.

All of these would work:

But this one won't work:

...because the slot will be expecting a QObject that the signal will not send. This connection will report a runtime error.

Advanced Signals and Slots Usage

For cases where you may require information on the sender of the signal, Qt provides the QObject::sender() function, which returns a pointer to the object that sent the signal.

The QSignalMapper class is provided for situations where many signals are connected to the same slot and the slot needs to handle each signal differently.

Suppose you have three push buttons that determine which file you will open: 'Tax File', 'Accounts File', or 'Report File'.

Qt Private Slot Example Software

In order to open the correct file, you use QSignalMapper::setMapping() to map all the clicked() signals to a QSignalMapper object. Then you connect the file's QPushButton::clicked() signal to the QSignalMapper::map() slot.

Then, you connect the mapped() signal to readFile() where a different file will be opened, depending on which push button is pressed.

Qt private slot example for real

Note: The following code will compile and run, but due to signature normalization, the code will be slower.

Using Qt with 3rd Party Signals and Slots

It is possible to use Qt with a 3rd party signal/slot mechanism. You can even use both mechanisms in the same project. Just add the following line to your qmake project (.pro) file.

It tells Qt not to define the moc keywords signals, slots, and emit, because these names will be used by a 3rd party library, e.g. Boost. Then to continue using Qt signals and slots with the no_keywords flag, simply replace all uses of the Qt moc keywords in your sources with the corresponding Qt macros Q_SIGNALS (or Q_SIGNAL), Q_SLOTS (or Q_SLOT), and Q_EMIT.

See also Meta-Object System and Qt's Property System.

© 2016 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.