Qt Meta Object
Reference Links
The Meta Object
- Qt provides a meta-object system.
- Meta-object (literally “over the object”) is a way to achieve some programming paradigms that are normally impossible to achieve with pure C++ like:
- Introspection: capability of examining a type at run-time
- Asynchronous function calls
- To use such Meta-object capabilities in an application, one can subclass QObject and mark it so that the meta-object compiler (moc) can interpret and translate it.
- Code produced by moc includes
- signals and slots signatures,
- methods that are used to retrieve meta-information from those marked classes, properties handling…
- All this information can be accessed using the following method:
const QMetaObject * QObject::metaObject() const
- Meta-object (literally “over the object”) is a way to achieve some programming paradigms that are normally impossible to achieve with pure C++ like:
- QMetaObject class contains all the methods that deal with meta-objects.
Important macros
- The most important macro is Q_OBJECT.
- Signal-Slot connections and their syntax cannot be interpreted by a regular C++ compiler.
- The moc is provided to translate the QT syntax like “connect”, “signals”, “slots”, etc into regular C++ syntax.
class MyWidget : public QWidget { Q_OBJECT public: MyWidget(QWidget *parent=nullptr); }
- Others marker macros for moc are
- signals
- public / protected / private slots
that mark the different methods that need to be extended.
-
SIGNAL and SLOT are also two very important and useful macros.
- When a signal is emitted, the meta-object system is used to compare the signature of the signal, to check the connection, and to find the slot using it’s signature.
- These macros are actually used to convert the provided method signature into a string that matches the one stored in the meta-object.
- The moc is provided to translate the QT syntax like “connect”, “signals”, “slots”, etc into regular C++ syntax.
- Signal-Slot connections and their syntax cannot be interpreted by a regular C++ compiler.
Creating custom signals and slots
- Creating custom slots
- Slots are like normal methods, but with small decorations around,
- Creating custom signals
- Signals need little to no implementation at all.
- Checklist:
- add Q_OBJECT macro
- add signals section, and write signals prototypes
- add public slots or protected slots or private slots sections, and write slots prototypes
- implement slots as normal methods
- establish connections
Creating custom slots
- In order to implement a slot, we first need to make the class be able to send signals and have slots.
- This is done by setting the Q_OBJECT macro in the class declaration (often in the header).
- After that, a slot should be declared in the corresponding section, and implemented as a normal method.
- Finally, slots are connected to signals.
Creating signals
- As for slots, we first need to add the Q_OBJECT macro.
- Signals should also be declared in the signals section, and there is no need for them to be implemented.
- They are emitted using the emit keyword:
emit mySignal();
- Note that in order to send signals that have parameters, you have to pass them in the signal emission:
emit mySignal(firstParameter, secondParameter ...);
Example
Creating custom slots
- Let’s start with our window with the button:
#ifndef WINDOW_H
#define WINDOW_H
#include <QWidget>
class QPushButton;
class Window : public QWidget
{
Q_OBJECT
public:
explicit Window(QWidget *parent = nullptr);
private slots:
void slotButtonClicked(bool checked);
private:
QPushButton* m_pButton;
signals:
};
#endif // WINDOW_H
#include "window.h"
#include <QPushButton>
Window::Window(QWidget *parent) : QWidget(parent)
{
// Set size of the window
setFixedSize(100, 50);
// Create and position the button
m_pButton = new QPushButton("Hello World", this);
m_pButton->setGeometry(10, 10, 80, 30);
// New: Do the connection
// connect(m_pButton, SIGNAL (clicked()), QApplication::instance(), SLOT (quit()));
m_pButton->setCheckable(true);
connect(m_pButton, SIGNAL (clicked(bool)), this, SLOT (slotButtonClicked(bool)));
}
void Window::slotButtonClicked(bool checked) {
if (checked) {
m_pButton->setText("Checked");
} else {
m_pButton->setText("Hello World");
}
}
- New Button Action
- can be checked
- when checked, it displays “checked”
- when unchecked, it restores “Hello World”
signals: void QPushButton::clicked(bool checked) private slots: void Window::slotButtonClicked(bool checked);
- Implement private and protected slots by prefixing them with “slot”
- can be checked
Emitting custom signals
- New Button Action
- close the app. after clicking 10 times
- implement a counter that count the number of clicks
- close the app. after clicking 10 times
class Window : public QWidget
{
Q_OBJECT
public:
explicit Window(QWidget *parent = nullptr);
signals:
void counterReached();
private slots:
void slotButtonClicked(bool checked);
private:
QPushButton* m_pButton;
int m_nCounter;
};
- add “signals” section in the header
- Even if the signal is declared as a method, there is no need to implement it. The meta-compiler is used to do this.
- Now we need to emit the signal when the counter reaches 10.
#include <QPushButton>
#include <QApplication>
Window::Window(QWidget *parent) : QWidget(parent)
{
// Set size of the window
setFixedSize(100, 50);
// Create and position the button
m_pButton = new QPushButton("Hello World", this);
m_pButton->setGeometry(10, 10, 80, 30);
m_pButton->setCheckable(true);
m_nCounter = 0;
// New: Do the connection
connect(m_pButton, SIGNAL (clicked(bool)), this, SLOT (slotButtonClicked(bool)));
connect(this, SIGNAL (counterReached()), QApplication::instance(), SLOT (quit()));
}
void Window::slotButtonClicked(bool checked) {
if (checked) {
m_pButton->setText("Checked");
} else {
m_pButton->setText("Hello World");
}
m_nCounter++;
if (m_nCounter == 10){
emit counterReached();
}
}
- We need t o write the keyword emit to send the signal.
Troubleshooting
While compiling your program, especially when you are adding the macro Q_OBJECT, you might have this compilation error.
main.cpp:(.text._ZN6WindowD2Ev[_ZN6WindowD5Ev]+0x3): undefined reference to `vtable for Window'
This is because of the meta-object compiler not being run on a class that should have meta-object. You should rerun qmake, by doing Build > Run qmake.
Widgets
QRadioButton
- Radio button is a standard GUI component being used to make a unique choice from a list.
- QRadioButton behaves just like QPushButton thanks to a nice inheritance.
- By default, QRadioButton are not grouped, therefore more than one of them can be checked at the same time. In order to have the “exclusive” behaviour of many radio buttons, we need to use QButtonGroup.
- QButtonGroup
- Allocate a new button group
- Attach it to the parent object
- e.g.)
- MainWindow
- this
QButtonGroup* pButtonGroup = new QButtonGroup(object); // Add buttons in the button group pButtonGroup->addButton(button1); pButtonGroup->addButton(button2); pButtonGroup->addButton(button3);
- e.g.)