graphical interfaces in Qt
Eric Lecolinet - Télécom ParisTech www.telecom-parist.fr/~elc 2020
Eric Lecolinet - Télécom ParisTech - Qt et graphique interactif
Filière IGR and IGD Master
http://www.telecom-paris.fr/~elc/igr/
http://www.telecom-paristech.fr/~elc/
Eric Lecolinet - Télécom ParisTech - Qt et graphique interactif http://www.telecom-paris.fr/~elc/igr 3 Filière IGR (2a + 3a)
comporte des informations sur la 3e année et les séjours http://www.telecom-paristech.fr/~elc/igr/ à l'étranger !
Eric Lecolinet - Télécom ParisTech - Qt et graphique interactif 4 IGR201b: Interactive 2D/Mobile/Web development
IGR201a: Interactive 3D application development - Basic digital imaging - OpenGL
IGR201b - Qt GUI toolkit - Android - Web interface basics
http://www.telecom-paristech.fr/~elc/igr201/
Eric Lecolinet - Télécom ParisTech - Qt et graphique interactif 5 Qt ("cute")
A versatile environnement including - A powerful cross-platform graphical toolkit (including iOS and Android) - A large set of libraries - Used in various open-source or commercial products
Dual-licensed - LGPL licence (free): open-source code, student/academic/hobby projects, etc. - Commercial licence: for companies
Eric Lecolinet - Télécom ParisTech - Qt et graphique interactif 6 Qt WebEngine WidgetsThe Qt WebEngine Widgets module provides a web browser engine as well as C++ classes to render and interact with web content. Qt WebKit Widgets The Qt WebKit Widgets module provides a web browser engine as well as C++ classes to render and interact with web content. Qt3DCore Qt3D Core module contains functionality to support near-realtime simulation systems Qt3DInput Qt3D Input module provides classes for handling user input in applications using Qt3D Qt3DRenderer Qt3D Renderer module contains functionality to support 2D and 3D rendering using Qt3D QtBluetooth Enables basic Bluetooth operations like scanning for devices and connecting them QtConcurrent Qt Concurrent module contains functionality to support concurrent execution of program code QtCore Provides core non-GUI functionality QtDBus Qt D-Bus module is a Unix-only library that you can use to perform Inter-Process Communication using the D-Bus protocol QtDesigner Provides classes to create your own custom widget plugins for Qt Designer and classes to access Qt Designer components QtGui Qt GUI module provides the basic enablers for graphical applications written with Qt QtHelp Provides classes for integrating online documentation in applications QtLocation Provides C++ interfaces to retrieve location and navigational information QtMultimedia Qt Multimedia module provides audio, video, radio and camera functionality QtNetwork Provides classes to make network programming easier and portable QtNfc An API for accessing NFC Forum Tags QtOpenGL Qt OpenGL module offers classes that make it easy to use OpenGL in Qt applications QtPositioning Positioning module provides positioning information via QML and C++ interfaces QtPrintSupport Qt PrintSupport module provides classes to make printing easier and portable QtQml C++ API provided by the Qt QML module QtQuick Qt Quick module provides classes for embedding Qt Quick in Qt/C++ applications QtQuickWidgets C++ API provided by the Qt Quick Widgets module QtScript Qt Script module provides classes for making Qt applications scriptable QtScriptTools Provides additional components for applications that use Qt Script QtSensors Provides classes for reading sensor data QtSerialPort List of C++ classes that enable access to a serial port QtSql Provides a driver layer, SQL API layer, and a user interface layer for SQL databases QtSvg Qt SVG module provides functionality for handling SVG images QtTest Provides classes for unit testing Qt applications and libraries QtUiTools Provides classes to handle forms created with Qt Designer QtWebChannel List of C++ classes that provide the Qt WebChannel functionality QtWebSockets List of C++ classes that enable WebSocket-based communication QtWidgets Qt Widgets module extends Qt GUI with C++ widget functionality QtXml Qt XML module provides C++ implementations of the SAX and DOM standards for XML QtXmlPatterns Qt XML Patterns module provides support for XPath, XQuery, XSLT and XML Schema validat Eric Lecolinet - Télécom ParisTech - Qt et graphique interactif 7 Tools & computer languages
Tools - IDE: QtCreator (QtDesigner) - Internationalization: Qt Linguist - Documentation: Qt Assistant - qmake, etc.
Computer languages - Natively written in C++
- Various bindings, especially PyQt (Python)
- Qt Quick: based on the QML declarative langage (similar to CSS & JSON)
Eric Lecolinet - Télécom ParisTech - Qt et graphique interactif 8 Useful Links
- Télécom Labs: http://www.telecom-paristech.fr/~elc/qt
- Qt Web site: http://www.qt.io/
- GUI Toolkit: • Main page: http://doc.qt.io/qt-5/ • All modules: http://doc.qt.io/qt-5/modules-cpp.html
- Qt Widgets: • Documentation : http://doc.qt.io/qt-5/qtwidgets-index.html
• List of classes: http://doc.qt.io/qt-5/qtwidgets-module.html
Eric Lecolinet - Télécom ParisTech - Qt et graphique interactif 9 Main widgets
Inheritance graph
QObject: root class
QWidget: base class of all graphical objects
Eric Lecolinet - Télécom ParisTech - Qt et graphique interactif 10 Interactors
QLabel
QPushButton
QSlider
QLineEdit
QTextEdit
etc.
Eric Lecolinet - Télécom ParisTech - Qt et graphique interactif 11 Containers
A QWidget can contain other widgets QToolbox
There as also special purpose containers
QFrame
QStackedWidget QGroupBox
QTabWidget
Eric Lecolinet - Télécom ParisTech - Qt et graphique interactif 12 Main window and dialog boxes
QFileDialog
QMainWidget
Eric Lecolinet - Télécom ParisTech - Qt et graphique interactif QMessageBox 13 Note: C++ vs Java
MyClass.java MyClass.h class MyClass { class MyClass { public void whatever(int i) { public: Zombat z = new Zombat(i); void whatever(int i); z.foo(); } ; } }
MyClass.cpp Some Differences in C++ void MyClass::whatever(int i) { Zombat * z = new Zombat(); • header + implementation files (not mandatory) z->foo(); } • final ; for classes • don't forget the * • -> instead of . for accessing members
Eric Lecolinet - Télécom ParisTech - Qt et graphique interactif 14 Note: C++ vs Java
MyClass2.cpp MyClass.h void MyClass::whatever(int i) { class MyClass { Zombat z = new Zombat(); public: z.foo(); void whatever(int i); } };
Correct? MyClass.cpp MyClass3.cpp void MyClass::whatever(int i) { void MyClass::whatever(int i) { Zombat * z = new Zombat(); Zombat z = Zombat(); z->foo(); z.foo(); } }
Correct?
Eric Lecolinet - Télécom ParisTech - Qt et graphique interactif 15 Note: C++ vs Java
MyClass2.cpp MyClass.h void MyClass::whatever(int i) { class MyClass { Zombat z = new Zombat(); public: z.foo(); void whatever(int i); }; };
NOT Correct! MyClass.cpp MyClass3.cpp void MyClass::whatever(int i) { void MyClass::whatever(int i) { Zombat * z = new Zombat(); Zombat z = Zombat(); z->foo(); z.foo(); } };
Means something different!
Eric Lecolinet - Télécom ParisTech - Qt et graphique interactif 16 Hello Word!
#include
• show() : the widget is displayed • hello becomes the top-level widget because it has no parent (see later) • exec() : starts the event loop
Eric Lecolinet - Télécom ParisTech - Qt et graphique interactif 17 Event loop
Calls callback methods (slots)
Event Updates widgets
Event loop User
The event loop • Takes control : exec() blocks the program while (true) { event = getNextEvent() • Indefinitely: processEvent(event); • waits for the next event } • processes the event basic event loop
Eric Lecolinet - Télécom ParisTech - Qt et graphique interactif 18 Instance graph
A QWidget can contain QWidgets that contain QWidgets...
= instance graph (more precisely it's a tree)
parenthood means:
• superimposition: children on top of parents
• clipping : children parts outside parent area not visible
Eric Lecolinet - Télécom ParisTech - Qt et graphique interactif 19 Instance graph
#include
int main( int argc, char **argv ) { auto * app = new QApplication(argc, argv);
auto * box = new QWidget(); quitBtn box->resize(200, 120);
auto * quitBtn = new QPushButton("Quit", box); // box is the parent of quitBtn quitBtn->resize(100, 50); quitBtn->move(50, 35); quitBtn->setFont( QFont("Times", 18, QFont::Bold) );
box->show( ); The parent is given as an argument of the constructor return app->exec( ); } Except for "top-level" widgets (no parent)
Note auto keyword Eric Lecolinet - Télécom ParisTech - Qt et graphique interactif 20 Signals and slots
#include
int main( int argc, char **argv ) { auto * app = new QApplication(argc, argv);
auto * box = new QWidget(); box->resize(200, 120);
auto * quitBtn = new QPushButton("Quit", box); // etc....
QObject::connect( quitBtn, SIGNAL(clicked( )), app, SLOT(quit( )) ); // connects a signal to a slot
box->show( ); return app->exec( ); }
Eric Lecolinet - Télécom ParisTech - Qt et graphique interactif 21 Signals and slots
A signal is emitted by an object – e.g. when clicking a Push Button
A slot is a method – that can be connected to a signal
When a signal is emitted, the connected slots are executed
– A signal can be connected to several slots – Several signals can be connected to a slot
Eric Lecolinet - Télécom ParisTech - Qt et graphique interactif 22 Signals and slots
#include
int main( int argc, char **argv ) { auto * app = new QApplication(argc, argv);
auto * box = new QWidget(); box->resize(200, 120);
auto * quitBtn = new QPushButton("Quit", box); // etc....
QObject::connect( quitBtn, SIGNAL(clicked( )), app, SLOT(quit( )) );
box->show( ); return app->exec( ); }
standard signal slot (method) of QPushButton of QApplication
Eric Lecolinet - Télécom ParisTech - Qt et graphique interactif 23 Signals and slots
Key aspect of Qt - differs from callback functions or Java listeners - require a pre-compilation step
Signals and slots can have arguments - which must correspond (same order, same types) - previous example: connect( quitBtn, SIGNAL(clicked( )), app, SLOT(quit( )) );
- here stateChanged() holds an int that is received by mySlot(): connect( checkBox, SIGNAL(stateChanged(int)), y, SLOT(mySlot(int)) );
- OK because a slot can have less arguments than a signal: connect( checkBox, SIGNAL(stateChanged(int)), app, SLOT(quit()) );
Eric Lecolinet - Télécom ParisTech - Qt et graphique interactif 24 Declaring a slot
In the header file (.h)
• MyClass must derive from QObject class MyClass : public QWidget { • or any widget class Q_OBJECT public: • keywords Q_OBJECT and slots MyClass( );
• needed by the moc pre-compiler public slots: void mySlot( int value ); • slots must be implemented }; • usually, in the .cpp file
Eric Lecolinet - Télécom ParisTech - Qt et graphique interactif 25 Alternate syntax
QObject::connect(quitBtn, &QPushButton::clicked, app, &QApplication::quit);
- relies on C++ method pointers
- benefits : the C++ compiler checks there is no error
- drawbacks : less powerful, not compatible with QtQuick
Eric Lecolinet - Télécom ParisTech - Qt et graphique interactif 26 Using lambdas
void MyClass::foo() { int val = 10; QObject::connect(quitBtn, &QPushButton::clicked, [=] {myObj->setBalance (val);} ); }
[=] {myObj->setBalance(value);} is a lambda
[=] means that the lambda captures this and the value of local variables
Eric Lecolinet - Télécom ParisTech - Qt et graphique interactif 27 Using lambdas
void MyClass::foo() { int val = 10; QObject::connect(quitBtn, &QPushButton::clicked, [=] {myObj->setBalance (val);} ); }
[=] {myObj->setBalance(value);} is a lambda
[=] means that the lambda captures this and the value of local variables
[&] means it captures variables by reference => variables' values can be changed in the lambda... => as they are not copied they must still exist (program crash otherwise!)
Eric Lecolinet - Télécom ParisTech - Qt et graphique interactif 28 Misc.
Disconnection
disconnect(x, SIGNAL(balanceChanged(int)), y, SLOT(setBalance(int)) );
Propagates the signal
connect(x, SIGNAL(balanceChanged(int)), controller, SIGNAL(changed(int)) );
Eric Lecolinet - Télécom ParisTech - Qt et graphique interactif 29 Signals and slots compilation
Meta Object Compiler (MOC) - pre-processor - generates additional code (signal / slots table) - caution: do not forget the Q_OBJECT keyword
Use QtCreator or the qmake command - in the directory containing the source files:
• qmake -project // creates xxx.pro • qmake // creates the Makefile (or equivalent) • make // creates .moc and binary files
Eric Lecolinet - Télécom ParisTech - Qt et graphique interactif 30 Main Window (QMainWindow)
Predefined areas for: - a menubar - a toolbar - a statusbar - a central area (working area)
Principle - Create a subclass QMainWindow
- Its constructor must create the widgets
Eric Lecolinet - Télécom ParisTech - Qt et graphique interactif 31 Main Window
In the constructor of a class deriving from de QMainWindow
QMenuBar * menubar = this->menuBar( ); // adds/returns the menu bar QMenu * menu = menubar->addMenu( tr("&File") ); // adds a pulldown menu
// new.png is specified in a resource file (see later) QAction * action = new QAction( QIcon(":/new.png"), tr("&New..."), this ); menu->addAction(action); // adds the action to the menu connect(action, SIGNAL(triggered( )), this, SLOT(open( ))); // connection
action->setShortcut( tr("Ctrl+N") ); // hot key action->setToolTip( tr("New file") ); // tool tip action->setStatusTip( tr("New file") ); // info on status bar
Eric Lecolinet - Télécom ParisTech - Qt et graphique interactif 32 Main Window
Actions – can both be added to menus and toolbars
QToolBar * toolbar = this->addToolBar( tr("File") ); toolbar->addAction(action);
Central area
QTextEdit * text = new QTextEdit(this); this->setCentralWidget(text);
Internationalization
– tr( ) translates the text
Eric Lecolinet - Télécom ParisTech - Qt et graphique interactif 33 Dialog boxes
QMessageBox
QFileDialog
Eric Lecolinet - Télécom ParisTech - Qt et graphique interactif 34 Modal dialog box
QString fileName = QFileDialog::getOpenFileName(this, tr("Open Image"), // title "/home/jana", // directory tr("Image Files (*.png *.jpg *.bmp)") // filter );
A modal dialog box blocks the interaction: => it forces the user to answer • Advantage: easy to program! • Drawback: not always very convenient for the user
Eric Lecolinet - Télécom ParisTech - Qt et graphique interactif 35 Modal dialog box
More generally
QFileDialog dialog = new QFileDialog(parent); dialog->setFilter("Text files (*.txt)"); QStringList fileNames;
if (dialog->exec( ) == QDialog::Accepted) { name1 = dialog->selectedFiles(); QString name1 = fileNames[0]; ... }
dialog.exec (or getOpenFileName) start a secondary event loop
Eric Lecolinet - Télécom ParisTech - Qt et graphique interactif 36 Internationalized text
Problem - so many languages, so many symbols! - solution: UNICODE
QString: Unicode strings • made of QChars (16 bits each) • one symbol = 1 QChar (usual case) or 2 QChar (more exotic symbols, e.g. Emojis)
To convert a QString • qPrintable(string) : converts to local encoding • toAscii( ) : ASCII 8 bits • toUtf8( ) : UTF-8 Unicode multibyte (1 char = 1 à 4 octets) • toLocal8Bit( ) : local encoding 8 bits • etc.
Eric Lecolinet - Télécom ParisTech - Qt et graphique interactif 37 Internationalized text
QFile: for opening files
QFile file( fileName ); if ( file.open( QIODevice::ReadOnly | QIODevice::Text) ) { .... } if ( file.open( QIODevice::WriteOnly ) ) { ... }
QTextStream: for reading or writing text from a QFile
QFile file("output.txt"); if (file.open( QIODevice::WriteOnly )) { QTextStream out( &file ); out << "Result: " << 10 << " " << 3.14; // writes on out }
Eric Lecolinet - Télécom ParisTech - Qt et graphique interactif 38 Debugging qDebug: for displaying debugging messages
#include
int val; QString s; qDebug( ) << "value: " << s << " / " << val;
// or, using standard C++ IO std::cout << "value: " << qPrintable(s) << " / " << val << std::endl;
don't forget endl !
Eric Lecolinet - Télécom ParisTech - Qt et graphique interactif 39 Reading text
• To read a word : stream >> arg1 >> arg2; // stops reading before a space
• To read a line : stream.readLine( size ); // returns the line, no size limit if size = 0
• To read the whole text file : stream.readAll( ); // only for small files!
• codecs : • setCodec(codec), setAutoDetectUnicode(bool);
Eric Lecolinet - Télécom ParisTech - Qt et graphique interactif 40 Ressources: internationalization
QAction * action = new QAction( tr("&New..."), this );
• tr() sert à translates the text if there is a dictionary in the resource files
• see QLinguist
Eric Lecolinet - Télécom ParisTech - Qt et graphique interactif 41 Ressources : Icons
QAction * action = new QAction( QIcon(":/images/new.png"), tr("&New..."), this );
: filename that is relative to the application here new.png is in sub-directory images
Caution!
The Prefix in QtCreator must be empty or /
Eric Lecolinet - Télécom ParisTech - Qt et graphique interactif 42 Ressource file
Eric Lecolinet - Télécom ParisTech - Qt et graphique interactif 43 Styles & Style Sheets
QStyle: Emulates the native "look and feel" - Look and feel is simulated and can be changed (as with Swing)
QStyleSheet: for customizing the "look" - Using CSS-like files
myTextEdit->setStyleSheet("color: blue;" "background-color: yellow;" "selection-color: yellow;" "selection-background-color: blue;");
Eric Lecolinet - Télécom ParisTech - Qt et graphique interactif 44 Layout
Goals • Text size depends on language => internationalization • Make it possible to resize interactively properly • Avoid making complex calculations
Eric Lecolinet - Télécom ParisTech - Qt et graphique interactif 45 Layout
QHBoxLayout, QVBoxLayout, QGridLayout
QFormLayout
QMainWindow Eric Lecolinet - Télécom ParisTech - Qt et graphique interactif 46 Layout example
QVBoxLayout * v_layout = new QVBoxLayout( ); v_layout->addWidget( new QPushButton( "OK" ) ); v_layout->addWidget( new QPushButton( "Cancel" ) ); v_layout->addStretch( ); v_layout->addWidget( new QPushButton( "Help" ) );
Layout objects
- can be nested - are independent from the widget tree (contrary to Java Swing)
- note addStretch
Eric Lecolinet - Télécom ParisTech - Qt et graphique interactif 47 Layout example
QVBoxLayout * v_layout = new QVBoxLayout( ); v_layout->addWidget( new QPushButton( "OK" ) ); v_layout->addWidget( new QPushButton( "Cancel" ) ); v_layout->addStretch( ); v_layout->addWidget( new QPushButton( "Help" ) );
QListBox * country_list = new QListBox( this ); countryList->insertItem( "Canada" ); ...etc...
QHBoxLayout * h_layout = new QHBoxLayout( ); h_layout->addWidget( country_list ); h_layout->addLayout( v_layout );
Eric Lecolinet - Télécom ParisTech - Qt et graphique interactif 48 Layout example
QVBoxLayout * v_layout = new QVBoxLayout( ); v_layout->addWidget( new QPushButton( "OK" ) ); v_layout->addWidget( new QPushButton( "Cancel" ) ); v_layout->addStretch( ); v_layout->addWidget( new QPushButton( "Help" ) );
QListBox * country_list = new QListBox( this ); countryList->insertItem( "Canada" ); ...etc...
QHBoxLayout * h_layout = new QHBoxLayout( ); h_layout->addWidget( country_list ); h_layout->addLayout( v_layout );
QVBoxLayout * top_layout = new QVBoxLayout( ); top_layout->addWidget( new QLabel( "Select a country", this ) ); top_layout->addLayout( h_layout );
window->setLayout( top_layout ); window->show( ); Eric Lecolinet - Télécom ParisTech - Qt et graphique interactif 49 Advanced layout control
For each QWidget • min and max sizes • a Size Policy
Methods • setMinimumSize(), setMaximumSize()
• setSizePolicy(QSizePolicy)
• setSizePolicy(QSizePolicy::Policy horizontal, QSizePolicy::Policy vertical)
• setHorizontalPolicy() • setVerticalPolicy()
Eric Lecolinet - Télécom ParisTech - Qt et graphique interactif 50 Advanced layout control
Size Policy = size constraints • sizeHint() = recommended size for the widget • Existing Size Policies • Fixed: = sizeHint() • Minimum: >= sizeHint() • Maximum: <= sizeHint() • Preferred: ~ sizeHint(), can be shrunk, can be expanded • Expanding: get as much space as possible, can be shrunk • MinimumExpanding: idem, but can't be shrunk • Ignored: idem, ignoring sizeHint()
Eric Lecolinet - Télécom ParisTech - Qt et graphique interactif 51 More on signal & slots
Slot executed by several objects Action 1 - signal / slot model => le slot does not know the emitter Slot doIt()
- but this can be useful!
=> shared slots Action 2
Solutions ?
Eric Lecolinet - Télécom ParisTech - Qt et graphique interactif 52 Solution 1: Lambdas
// instance variable of MyClass QAction * action1, * action2, …;
Action // in the .cpp file void MyClass::createGUI( ) { action1 = new QAction(tr("Action 1"), this); Slot connect( action1, &QAction::triggered, [=] {doIt(action1);} );
action2 = new QAction(tr("Action 2"), this); Action connect( action2, &QAction::triggered, [=] {doIt(action2);} ); …. } void MyClass::doIt(QAction * sender ) { if (sender == action1) ....; else if (sender == action2) .... ; …. }
Eric Lecolinet - Télécom ParisTech - Qt et graphique interactif 53 Solution 2: QObject::sender()
// instance variable of MyClass QAction * action1, * action2, …;
Action // in the .cpp file void MyClass::createGUI( ) { action1 = new QAction(tr("Action 1"), this); Slot connect( action1, SIGNAL(triggered()), this, SLOT(doIt()) );
action2 = new QAction(tr("Action 2"), this); Action connect( action2, SIGNAL(triggered()), this, SLOT(doIt()) ); ..… } void MyClass::doIt( ) { auto * sender = QObject::sender( ); // similar to getSource() in Java/Swing if (sender == action1) ....; else if (sender == action2) .... ; …. } Eric Lecolinet - Télécom ParisTech - Qt et graphique interactif 54 Solution 3: QActionGroup
// instance variable of MyClass QAction * action1, * action2, …;
// in the .cpp file void MyClass::createGUI( ) { Action 1 auto *group = new QActionGroup(this);
// only one connect ! connect(group, SIGNAL(triggered(QAction *)), Slot doIt() this, SLOT(doIt(QAction *)));
action1 = group->addAction(tr("Action 1")); action2 = group->addAction(tr("Action 2")); Action 2 … } void MaClasse::doIt(QAction * sender ) { ActionGroup if (sender == action1) ....; else if (sender == action2) .... ; …. Eric Lecolinet - Télécom ParisTech - Qt et graphique interactif 55 Solution 3: QActionGroup
By default, the group implements exclusive selection otherwise:
group->setExclusive(false);
Action 1
Same principle with buttons (QPushButton, QRadioButton, QCheckBox …) Slot doIt()
QButtonGroup * group = new QButtonGroup(this);
Action 2 QButtonGroup signals:
buttonClicked(QAbstractButton * button) ActionGroup buttonClicked(int id)
Eric Lecolinet - Télécom ParisTech - Qt et graphique interactif 56 Solution 4: QSignalMapper
void MyClass::createGUI( ) { QSignalMapper* mapper = new QSignalMapper (this) ; connect(mapper, SIGNAL(mapped(int)), this, SLOT(doIt(int))) ;
QPushButton * btn1 = new QPushButton("Action 1"), this); connect (btn1, SIGNAL(clicked( )), mapper, SLOT(map( ))) ; mapper->setMapping (btn1, 1) ;
QPushButton * btn2 = new QPushButton("Action 1"), this); connect (btn2, SIGNAL(clicked( )), mapper, SLOT(map( ))) ; mapper->setMapping (btn2, 2) ; … } void MaClasse::doIt(int value) { …. } Possible for : int, QString&, QWidget* et QObject*
Eric Lecolinet - Télécom ParisTech - Qt et graphique interactif 57 Creating one's own signals & slots
In the header file (.h) class BankAccount : public QObject { Q_OBJECT • Must be a subclass of QObject private: int curBalance; (or QWidget) public: BankAccount( ) { curBalance = 0; } • Note Q_OBJECT, slots int getBalance( ) const { return curBalance; } and signals keywords public slots: (needed by the moc pre-compiler) void setBalance( int newBalance ); signals: void balanceChanged( int newBalance ); • Implement slots };
• Don't implement signals (this is done by the moc)
Eric Lecolinet - Télécom ParisTech - Qt et graphique interactif 58 class BankAccount : public QObject { Q_OBJECT private: Implementing a slot int curBalance; public: BankAccount( ) { curBalance = 0; } int getBalance( ) const { return curBalance; } In the implémentation file (.cpp) public slots: void setBalance( int newBalance ); signals: void BankAccount::setBalance(int newBalance) void balanceChanged( int newBalance ); { }; if (newBalance != curBalance) { curBalance = newBalance; emit balanceChanged(curBalance); } }
emit • emits the balanceChanged() signal • the signal "holds" the curBalance value
Eric Lecolinet - Télécom ParisTech - Qt et graphique interactif 59 class BankAccount : public QObject { Q_OBJECT private: One way connection int curBalance; public: BankAccount( ) { curBalance = 0; } int getBalance( ) const { return curBalance; } public slots: void setBalance( int newBalance ); signals: void balanceChanged( int newBalance ); };
BankAccount * x = new BankAccount; BankAccount * y = new BankAccount; connect(x, SIGNAL(balanceChanged(int)), y, SLOT(setBalance(int))); x->setBalance(10);
void BankAccount::setBalance(int newBalance) { if (newBalance != curBalance) { curBalance = newBalance; emit balanceChanged(curBalance); } }
Eric Lecolinet - Télécom ParisTech - Qt et graphique interactif 60 class BankAccount : public QObject { Q_OBJECT private: One way connection int curBalance; public: BankAccount( ) { curBalance = 0; } int getBalance( ) const { return curBalance; } public slots: void setBalance( int newBalance ); signals: void balanceChanged( int newBalance ); };
BankAccount * x = new BankAccount; BankAccount * y = new BankAccount; connect(x, SIGNAL(balanceChanged(int)), y, SLOT(setBalance(int))); x->setBalance(10);
- x is set to 10 ➜ the balanceChanged() signal is emitted and holds this value
- setBalance() is executed on object y ➜ y is set to 10
Eric Lecolinet - Télécom ParisTech - Qt et graphique interactif 61 Two-way connection
connect(x, SIGNAL(balanceChanged(int)), y, SLOT(setBalance(int))); connect(y, SIGNAL(balanceChanged(int)), x, SLOT(setBalance(int))); x->setBalance(10);
- OK? void BankAccount::setBalance(int newBalance) { if (newBalance != curBalance) { curBalance = newBalance; emit balanceChanged(curBalance); } }
Eric Lecolinet - Télécom ParisTech - Qt et graphique interactif 62 Two-way connection
connect(x, SIGNAL(balanceChanged(int)), y, SLOT(setBalance(int))); connect(y, SIGNAL(balanceChanged(int)), x, SLOT(setBalance(int))); x->setBalance(10);
• OK : because emit is called void BankAccount::setBalance(int newBalance) only if newBalance has changed { if (newBalance != curBalance) { • infinite loop otherwise! curBalance = newBalance; emit balanceChanged(curBalance); } }
Eric Lecolinet - Télécom ParisTech - Qt et graphique interactif 63 Ignoring events
To ignore events
• QEvent::ignore() => The receptor ignores the event
Typical example: Custom behavior when quitting the application
• When clicking on the window bar close button
• The QEvent::closeEvent() method is called
Custom behavior void MainWindow::closeEvent(QCloseEvent *e) { • Redefine closeEvent() so that it calls ignore() e->ignore(); myMethod(); }
Eric Lecolinet - Télécom ParisTech - Qt et graphique interactif 64 2D Graphics
Eric Lecolinet - Télécom ParisTech - Qt et graphique interactif 65 Drawing in a widget
A widget is repainted "when needed" - When the application is started or restored (deiconified)
- When a window that was hiding a widget is moved
- When a window is moved (depending on settings)
- When requesting it by calling update( )
damaged / repaint model - Differs from 3D applications (usually, the scene is constantly repainted)
Eric Lecolinet - Télécom ParisTech - Qt et graphique interactif 66 Damaged / repaint model
void mySlot(...) ...... update(); ...... update(x, y, w, h); Event ...... update(region1); Event loop update(region2); User ...... }
void paintEvent(QPaintEvent* e) { ...... }
update() tells the system that an area has been damaged paintEvent() is then automatically called after processing slots
Eric Lecolinet - Télécom ParisTech - Qt et graphique interactif 67 Damaged / repaint model
Caution! • Draw only in paintEvent() • Don't call paintEvent() directly
Stores requests in a waiting list The area can be specified (whole widget area by default) called once whatever the number of update() calls
update() tells the system that an area has been damaged paintEvent() is then automatically called after processing slots
Eric Lecolinet - Télécom ParisTech - Qt et graphique interactif 68 Damaged / repaint model
In addition:
• repaint() redraw immediately (contrary to update()) • don't use it except in special cases (animations)
Java works in the same way but: • update() Qt == repaint() Java • paintEvent() Qt == paint() Java
Eric Lecolinet - Télécom ParisTech - Qt et graphique interactif 69 Drawing
Principle: create a subclass of QWidget that redefines paintEvent()
Canvas.h Canvas.cpp
#include
Use QPainter only in paintEvent() (because of double buffering)
Eric Lecolinet - Télécom ParisTech - Qt et graphique interactif 70 Drawing
Important! Canvas.cpp QPainter is allocated on the stack! #include
Eric Lecolinet - Télécom ParisTech - Qt et graphique interactif 71 Detecting events
Principle: create a subclass of QWidget that redefines these functions No signals / slots in this case!
void mousePressEvent(QMouseEvent*);
void mouseReleaseEvent(QMouseEvent*);
void mouseDoubleClickEvent(QMouseEvent*); Note: detects drag events void mouseMoveEvent(QMouseEvent*); if setMouseTracking(true) was called
void setMouseTracking(bool) Drag event = move with mouse button pressed bool hasMouseTracking()
Eric Lecolinet - Télécom ParisTech - Qt et graphique interactif 72 Detecting events
Canvas.h Canvas.cpp #include
QMouseEvent methods • button() Mouse bouton that triggered the event. ex: Qt::LeftButton
• buttons() State of the other buttons (ORed mask). ex: Qt::LeftButton | Qt::MidButton
• modifiers() Keyboard modifiers. ex: Qt::ControlModifier | Qt:: ShiftModifier
Eric Lecolinet - Télécom ParisTech - Qt et graphique interactif 73 Cursor position
QMouseEvent methods Canvas.cpp #include "Canvas.h" • Local position of the event (relative to widget): void Canvas::mousePressEvent(QMouseEvent* e) { pos( ) if (e->button() == Qt::LeftButton) { localPos( ) ...... ….. • Position relative to screen or window: update(); // dont forget! screenPos( ) } windowPos( ) } • When moving a widget interactively: globalPos( ) Changing coordinates • QWidget::mapToGlobal( ) Alternate way • QCursor::pos( ) : position of the cursor • QWidget::mapFromGlobal( )
Eric Lecolinet - Télécom ParisTech - Qt et graphique interactif 74 QPainter
Attributes • setPen( ) : how lines and outlines are drawn • setBrush( ) : how space if filled inside line • setFont( ) : text fonts • setTransform( ) : geometrical transformations • setClipRect/Path/Region( ) : clipping • setCompositionMode( ) : composing (e.g. alpha blending)
Drawing • drawPoint(), drawPoints(), drawLine(), drawLines() • drawRect(), drawRects(), fillRect(), • drawArc(), drawEllipse() • drawPolygon(), drawPolyline() Classes • drawPath(), fillPath() : combination of graphical primitives • QPoint, QLine, QRect... • drawText() • QPointF, QLineF • drawPixmap(), drawImage(), drawPicture(), • QPainterPath • etc. • QRegion • etc. Eric Lecolinet - Télécom ParisTech - Qt et graphique interactif 75 QPen
Attributes // in paintEvent() • style default value is 0 QPen pen; // default pen • width = "cosmetic pen" pen.setStyle(Qt::DashDotLine); • brush pen.setWidth(3); • capStyle pen.setBrush(Qt::green); • joinStyle pen.setCapStyle(Qt::RoundCap); pen.setJoinStyle(Qt::RoundJoin);
QPainter painter(this); Qt::PenStyle painter.setPen(pen); // etc....
Qt::PenCapStyle
Qt::PenJoinStyle
Eric Lecolinet - Télécom ParisTech - Qt et graphique interactif 76 QBrush
Attributes • style • color • gradient • texture Qt::GlobalColor (predefined colors)
QLinearGradient
Qt::BrushStyle QRadialGradient QLinearGradient gradient( QPointF(0, 0), QPointF(100, 100) );
gradient.setColorAt(0, Qt::white); QConicalGradient gradient.setColorAt(1, Qt::blue);
QBrush brush(gradient);
Eric Lecolinet - Télécom ParisTech - Qt et graphique interactif 77 Compositing
Porter Duff operators
• Specify: F(source, destination) • QPainter::setCompositionMode()
• Default: alpha blending (SourceOver mode)
• dest <= asrc * source + (1-asrc) * adest * dest
Limitations • hardware • implementation • what your are drawing on
Eric Lecolinet - Télécom ParisTech - Qt et graphique interactif 78 Clipping
According to a rectangle, a region, a path - QPainter::setClipping(), setClipRect(), setClipRegion(), setClipPath()
QRegion operations - united(), intersected(), subtracted(), xored()
QRegion r1(QRect(100, 100, 200, 80), QRegion::Ellipse); // r1: elliptic region QRegion r2(QRect(100, 120, 90, 30)); // r2: rectangular region QRegion r3 = r1.intersected(r2); // r3: intersection
QPainter painter(this); painter.setClipRegion(r3); ...etc...
Eric Lecolinet - Télécom ParisTech - Qt et graphique interactif 79 Geometrical transformations
• translate() • rotate() See Qt demos • scale() • shear() • setTransform()
Clock example
QPainter painter( this ); painter.translate( width( )/2, height( )/2 ); painter.scale( side/200.0, side/200.0 );
painter.save( ); // empile l’état courant painter.rotate( 30.0 * ((time.hour() + time.minute() / 60.0)) ); painter.drawConvexPolygon( hourHand, 3 ); painter.restore( ); // dépile
Eric Lecolinet - Télécom ParisTech - Qt et graphique interactif 80 Picking / Interaction
Example • Clicking on the rectangle • Centers the rectangle
QRect rect;
void mousePressEvent(QMouseEvent* e) { if (rect.contains( e->pos() )) { Tests rect.moveCenter( e->pos() ); • intersects() update( ); } • contains() • Methods of QRect, QRectF, void paintEvent(QPaintEvent* e ) { QPainterPath, etc. QPainter painter(this); • return true or false ..... painter.drawRect(rect); Returns the intersection } • intersected()
Eric Lecolinet - Télécom ParisTech - Qt et graphique interactif 81 Antialiasing
Anti-aliasing • To display "smooth contours" • Consequence of pixel discrete geometry • Especially useful for rendering fonts (e.g. ClearType)
what you see oeil.jpg what is actually displayed
subpixel rendering aliased antialiased Eric Lecolinet - Télécom ParisTech - Qt et graphique interactif 82 Paths
QPainterPath • Arbitrary combinations of lines and curves • displayed using QPainter::drawPath() • various graphical operations (e.g. clipping)
Methods - Moving the pen: moveTo(), arcMoveTo() - Drawing: lineTo(), arcTo() - Bezier curves: quadTo(), cubicTo() - addRect(), addEllipse(), addPolygon(), addPath() ... - addText() - translate(), etc.
Eric Lecolinet - Télécom ParisTech - Qt et graphique interactif 83 Path examples
QPointF center, startPoint; QPainterPath myPath;
myPath.moveTo( center ); myPath.arcTo( boundingRect, startAngle, sweepAngle );
QPainter painter( this ); painter.setBrush( myGradient ); painter.setPen( myPen ); painter.drawPath( myPath );
QPointF baseline(x, y); QPainterPath myPath;
myPath.addText( baseline, myFont, "Qt" );
QPainter painter( this ); ... etc.... painter.drawPath( myPath );
Eric Lecolinet - Télécom ParisTech - Qt et graphique interactif 84 Path examples
QPainterPath path; path.addRect(20, 20, 60, 60); path.moveTo(0, 0); path.cubicTo(99, 0, 50, 50, 99, 99); path.cubicTo(0, 99, 50, 50, 0, 0);
QPainter painter(this); painter.fillRect(0, 0, 100, 100, Qt::white); painter.setPen(QPen(QColor(79, 106, 25), 1, Qt::SolidLine, Qt::FlatCap, Qt::MiterJoin)); painter.setBrush(QColor(122, 163, 39)); painter.drawPath(path);
Qt::OddEvenFill Qt::WindingFill (default)
Eric Lecolinet - Télécom ParisTech - Qt et graphique interactif 85 Images
RGB colors
QImage image(3, 3, QImage::Format_RGB32); QRgb value; value = qRgb(122, 163, 39); // 0xff7aa327 image.setPixel(0, 1, value); image.setPixel(1, 0, value)
Indexed colors
QImage image(3, 3, QImage::Format_Indexed8); QRgb value; value = qRgb(122, 163, 39); // 0xff7aa327 image.setColor(0, value); value = qRgb(237, 187, 51); // 0xffedba31 image.setColor(1, value); image.setPixel(0, 1, 0); image.setPixel(1, 0, 1);
Eric Lecolinet - Télécom ParisTech - Qt et graphique interactif 86 QPicture
To record and replay graphical primitives
Record: QPicture picture; QPainter painter; painter.begin( &picture ); // paint in picture painter.drawEllipse( 10,20, 80,70 ); // draw an ellipse painter.end( ); // painting done picture.save( "drawing.pic" ); // save picture
Replay : QPicture picture; picture.load( "drawing.pic" ); // load picture QPainter painter; painter.begin( &myImage ); // paint in myImage painter.drawPicture( 0, 0, picture ); // draw the picture at (0,0) painter.end( ); // painting done
Eric Lecolinet - Télécom ParisTech - Qt et graphique interactif 87 Graphics View Framework
Goals and benefits • Item-based approach (scene graph) • Model-view programming • => graphical objects automatically refreshed, automatic picking, etc. • => multiple views
Main classes QGraphicsScene scene; QGraphicsRectItem * rect = • QGraphicsScene scene.addRect( QRectF(0,0,100,100) ); • QGraphicsView QGraphicsItem *item = scene.itemAt(50, 50); • QGraphicsItem ..... • etc. QGraphicsView view( &scene ); view.show( );
Eric Lecolinet - Télécom ParisTech - Qt et graphique interactif 88 3D graphics with OpenGL
Principle
- Create a subclass o QOpenGLWidget and redefinine : • virtual void initializeGL( ) • virtual void resizeGL(int w, int h) • virtual void paintGL( )
- Call update( ) to ask the widget to be repainted
- Note : QtGraphicsView is also compatible with OpenGL
- See example on the course Qt Web site
Eric Lecolinet - Télécom ParisTech - Qt et graphique interactif 89 OpenGL : Box3D.h
#include
class Box3D : public QOpenGLWidget, protected QOpenGLFunctions { Q_OBJECT public: Box3D(QWidget * parent); public slots: void setXRot(int angle); void setYRot(int angle); void setZRot(int angle); signals: void xRotChanged(int angle); void yRotChanged(int angle); void zRotChanged(int angle); private: void initializeGL( ) override; void paintGL( ) override; void resizeGL(int w, int h) override;
int xRot, yRot, zRot; GLfloat red, green, blue; Eric}; Lecolinet - Télécom ParisTech - Qt et graphique interactif 90 OpenGL : Box3D.cpp
#include "Box3D.h" void Box3D::setXRot(int rot) { if (rot != xRot) { Box3D::Box3D(QWidget * parent) : QOpenGLWidget(parent) { xRot = rot; xRrot = yRot = zRot = 0.; emit xRotChanged(rot); red = green = blue = 0.; update( ); } } } void Box3D::initializeGL( ) { void Box3D::setYRot(int rot) { initializeOpenGLFunctions( ); // ne pas oublier ! if (rot != yRot) { glClearColor(0.0f, 0.0f, 0.0f, 0.0f); yRot = rot; glEnable(GL_DEPTH_TEST); emit yRotChanged(rot); glEnable(GL_CULL_FACE); update( ); glShadeModel(GL_SMOOTH); } glEnable(GL_LIGHTING); } glEnable(GL_LIGHT0); void Box3D::setZRot(int rot) { GLfloat lightPosition[4] = {0, 0, 10, 1}; if (rot != zRot) { glLightfv(GL_LIGHT0, GL_POSITION, lightPosition); zRot = rot; GLfloat lightColor[4] = {red, green, blue, 1}; glLightfv(GL_LIGHT0, GL_AMBIENT, lightColor); emit zRotChanged(rot); } update( ); } } Eric Lecolinet - Télécom ParisTech - Qt et graphique interactif 91 OpenGL : Box3D.cpp
void Box3D::paintGL( ) { glBegin(GL_TRIANGLES); glNormal3f(1,0, 0.707); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glVertex3f(1,-1,0); glVertex3f(1,1,0); glLoadIdentity(); glVertex3f(0,0,1.2); glTranslatef(0.0, 0.0, -10.0); glEnd(); glRotatef(xRot, 1.0, 0.0, 0.0); glRotatef(yRot, 0.0, 1.0, 0.0); glBegin(GL_TRIANGLES); glRotatef(zRot, 0.0, 0.0, 1.0); glNormal3f(0,1,0.707); glVertex3f(1,1,0); glBegin(GL_QUADS); glVertex3f(-1,1,0); glNormal3f(0,0,-1); glVertex3f(0,0,1.2); glVertex3f(-1,-1,0); glEnd(); glVertex3f(-1,1,0); glBegin(GL_TRIANGLES); glVertex3f(1,1,0); glNormal3f(-1,0,0.707); glVertex3f(1,-1,0); glVertex3f(-1,1,0); glEnd(); glVertex3f(-1,-1,0); glVertex3f(0,0,1.2); glBegin(GL_TRIANGLES); glEnd(); glNormal3f(0,-1,0.707); } glColor3f(1.0f, 0.0f, 0.0f); glVertex3f(-1,-1,0); void Box3D::resizeGL(int w, int h) { glColor3f(1.0f, 1.0f, 0.0f); int side = qMin(w, h); glVertex3f(1,-1,0); glViewport((w - side) / 2, (h - side) / 2, side, side); glColor3f(1.0f, 0.0f, 1.0f); glMatrixMode(GL_PROJECTION); glVertex3f(0,0,1.2); glLoadIdentity(); glEnd(); glOrtho(-2, +2, -2, +2, 1.0, 15.0); …. glMatrixMode(GL_MODELVIEW); Eric Lecolinet - Télécom ParisTech - Qt et graphique interactif } 92 OpenGL : MainWindow
MainWindow::MainWindow(QWidget *parent) : int main(int argc, char **argv) { QMainWindow(parent) QApplication app(argc, argv); { … QSurfaceFormat format; Box3D * box3d = new Box3D(parent); format.setDepthBufferSize(24); setCentralWidget(box3d); format.setStencilBufferSize(8); createSlider(box3d, SLOT(setXRot(int))); format.setProfile(QSurfaceFormat::CoreProfile); createSlider(box3d, SLOT(setYRot(int))); QSurfaceFormat::setDefaultFormat(format); createSlider(box3d, SLOT(setZRot(int))); … MainWindow mainwin; } mainwin.setWindowTitle("OpenGL Box"); mainwin.show( ); return app.exec( ); void MainWindow::createSlider(Box3D * box3d, const char * slot) } { QSlider * slider = new QSlider(QSlider::Horizontal, this); connect(slider, SIGNAL(valueChanged(int)), box3d, slot); Type of a slot }
Eric Lecolinet - Télécom ParisTech - Qt et graphique interactif 93 Performance issues
Eric Lecolinet - Télécom ParisTech - Qt et graphique interactif 94 Flicker and double buffering
Flicker - example : https://www.youtube.com/watch?v=QoZ8L1quWnc
Problem - Drawing directly on the screen - Makes the eye to perceive changes
Solution: double buffering
- 1) Draw in the back buffer (hidden)
- 2) Copy in the front buffer (on the screen)
AnandTech Eric Lecolinet - Télécom ParisTech - Qt et graphique interactif 95 Page flipping
Alternate solution
- Changes buffers instead of copying them
Oracle/JavaSE
Eric Lecolinet - Télécom ParisTech - Qt et graphique interactif 96 Tearing
Tearing • example : • https://www.youtube.com/watch?v=1nFBtTq0DHo
Problem • The back buffer is copied before the drawing is complete • Two different frames appear on the screen!
Solution - VSync (Vertical synchronization) - Drawback: slower!
Eric Lecolinet - Télécom ParisTech - Qt et graphique interactif 97 Triple buffering
Faster
• One of the 2 back buffers is always ready • The font buffer can be updated without waiting
Eric Lecolinet - Télécom ParisTech - Qt et graphique interactif 98 Latency
Problem - Interactive drawing - The drawing does not "follow" the mouse
Reason - Too many elements must be drawn!
Solution - Draw less elements! - Double buffering can't help!
Eric Lecolinet - Télécom ParisTech - Qt et graphique interactif 99 Latency
Solution 1: Skip some intermediary images - Drawback: jerky display
void mouseMoveEvent(QMouseEvent* e) ...... Events if (delay < MAX_DELAY) update(); }
Don't redisplay if delay is too long
QTimer can be used for this purpose void paintEvent(QPaintEvent* e) { ...... }
100
Eric Lecolinet - Télécom ParisTech - Qt et graphique interactif Latency
Solution 2: Backing store - Don't redraw all elements • Store the part that does not change in an image • Display the image + the part that changed
Eric Lecolinet - Télécom ParisTech - Qt et graphique interactif 101 Qt Designer
Files • calculator.pro • calculator.ui • calculator.h • calculator.cpp • main.cpp calculator.pro TEMPLATE = app FORMS = calculator.ui SOURCES = main.cpp HEADERS = calculator.h calculator.ui • fichier XML 102 Qt Designer
calculator.h calculator.cpp
#include "ui_calculator.h" #include "calculator.h"
class Calculator : public QMainWindow { Calculator::Calculator(QWidget * parent) : Q_OBJECT QMainWindow(parent), ui (new Ui::Calculator) public: { Calculator(QWidget * parent = 0); ui->setupUi(this); private : ...... Ui::Calculator * ui; } };
ui points to an object that contains the widgets created by Qt Designer
103 Linking with source code
How can we display the result of a calculation in a gadget created using Designer?
spinbox1 spinbox2 result
names given to these widgets in Designer 104 #include "ui_calculator.h" class Calculator : public QMainWindow { Hidden file Q_OBJECT ui_calculator.h public: Calculator(QWidget *parent =0); private : Ui::Calculator * ui; private slots : void on_spinbox1_valueChanged(int value); "auto-connect" slots void on_spinbox2_valueChanged(int value); };
#include "calculator.h void Calculator::on_spinbox1_valueChanged(int value) { result variable: QString res = QString::number(value); // or: QString res = QString::number(ui->spinbox1->value()); •its name is the name of the widget in Designer ui->result->setText(res); } •it is declared in ui_calculator.h
105 Auto-connection
spinbox1 spinbox2 result
•Name of the gadget in Designer: spinbox1 •Name of the signal: valueChanged •=> the slot on_spinbox1_valueChanged() is auto-connected
106 Dynamic loading
class Calculator : public QWidget { #include
spinbox1 = qFindChild
107 « Promotion »
Promote - Allows including instances of client classes in Designer
Eric Lecolinet - Télécom ParisTech - Qt et graphique interactif 108 Examples
QtCreator > Accueil
Eric Lecolinet - Télécom ParisTech - Qt et graphique interactif 109 Concurrency
Events are processed sequentially => The UI freezes if a slot or a callback function :
• Takes long time to execute void mySlot( ) ...... • Never returns update(); } Events or
void xxxEvent(QMouseEvent* e) Event Loop ...... update(); }
void paintEvent(QPaintEvent* e) { QWidget::paintEvent(e); QPainter.painter(this); ...... } Eric Lecolinet - Télécom ParisTech - Qt et graphique interactif 110 Concurrency
Events are processed sequentially => The UI freezes if a slot or a callback function : • Takes long time to execute • Never returns
Typical examples • Heavy calculations • Network applications (using sockets, etc.) • ex: Web browser • External sensors • ex: Kinect
Eric Lecolinet - Télécom ParisTech - Qt et graphique interactif 111 Threads
void mySlot() { starts a thread Events }
void myFunction() { executes in the thread sends back data and returns }
1st case: A slot launches a thread • mySlot returns immediately
• myFunction terminates later • ex : load a Web page
Eric Lecolinet - Télécom ParisTech - Qt et graphique interactif 112 Threads
void mySlot() { Events }
void myFunction() { executes in the thread while (true) { send data continuously } }
2nd case : A thread is constantly running • A server, a device, etc. sends data continuously • myFunction runs a loop • ex : retrieve Kinect data
Eric Lecolinet - Télécom ParisTech - Qt et graphique interactif 113 Threads
void mySlot() { Events }
void myFunction() { executes in the thread while (true) { send data continuously } }
In both cases : How can we display this data? • myFunction must not directly change widgets • because of the event loop the graphical interfaces "lives" in the main thread
• Same problem with most (all?) GUI toolkits
Eric Lecolinet - Télécom ParisTech - Qt et graphique interactif 114 QThread
void mySlot() { Events }
void QThread::run() { while (true) { getData(données); emit mysignal(données) } } QThread • Its run() method is executed in a new thread
• It can send signals to slots that are executed in the main loop
• connect() provides a queuing mechanism • 5th argument: Qt::ConnectionType
Eric Lecolinet - Télécom ParisTech - Qt et graphique interactif 115 QThread class Tracker : public QThread { class MyWindow : public QMainWindow { Q_OBJECT Q_OBJECT public: Tracker * tracker{}; Tracker(const QString& host, int port); public slots: signals: void showData(const QString& data); void dataReady(const QString& data); public: private: MyWindow(QWidget* par) : QMainWindow(par) { void run( ) { // executed in the thread tracker = new DTracker(hostname, port); bool ok = true; QString data; connect(tracker, SIGNAL(dataReady(QString)), this, SLOT(showData(QString)) while (ok) { Qt::QueuedConnection); data = .....; // retrieve the data emit dataReady(data); tracker->start(); // starts the thread } .... } } }; dataReady() and ShowData() live in different threads ! Eric Lecolinet - Télécom ParisTech - Qt et graphique interactif 116 QThread
Qt::ConnectionType • AutoConnection connect(tracker, SIGNAL(dataReady(QString)), • DirectConnection this, SLOT(showData(QString)) • QueuedConnection Qt::QueuedConnection); • etc.
See also • QtConcurrent framework • QSocketNotifier
Eric Lecolinet - Télécom ParisTech - Qt et graphique interactif 117