bases graphique designer Eric Lecolinet - Tlcom ParisTech www.telecom-paristech.fr/~elc Toolkit graphique complet en C++
- Puissant et relativement simple - Nombreux outils et extensions - Utilis dans de nombreux produits, base de l'environnement KDE - Dvelopp par TrollTech, puis Nokia - Licences LGPL (gratuite) et commerciale
Toolkit Qt
Toolkit graphique complet en C++
- Puissant et relativement simple - Nombreux outils et extensions - Utilis dans de nombreux produits, base de l'environnement KDE - Dvelopp par TrollTech, puis Nokia - Licences LGPL (gratuite) et commerciale
Extensions, outils
Extensions et outils
- internationalisation: QString et Unicode - support sockets, XML, SQL, etc. - Open GL multiplateformes - Outils de dveloppement:
Toolkit multi-plateformes
- Principaux OSs : Windows, Mac OS X, Linux/X11 - Plate-formes mobiles : Symbian, MeeGo, Embedded Linux, Windows Mobile
Liens
Liens utiles
- Site Tlcom : http://www.telecom-paristech.fr/~elc/qt - Site Nokia: http://qt.nokia.com/ - Documentation Qt 4.6 : http://doc.qt.nokia.com/4.6/ http://doc.qt.nokia.com/4.6/classlist.html http://doc.qt.nokia.com/4.6/classes.html - Documentation Qt 4.7 : http://doc.qt.nokia.com/4.7/
Principaux widgets
Arbre d'hritage
Deuxime version
#include <QApplication> #include <QLabel> int main(int argc, char **argv) { QApplication app(argc, argv); QLabel hello("Hello Qt!"); hello.resize(100, 30); hello.show( ); return app.exec( ); }
Remarques
- pointeurs C++ : attention aux -> et aux * - pas de ramasse miette ! - parent pass en argument ou NULL (par dfaut) pour "top-level" widgets - exec() lance la boucle de gestion des vnements
Remarques
- objets crs dans la pile => dtruits en n de fonction - la variable contient l'objet: . (point) pour accder aux champs - NB Qt3: il faudrait aussi: app.setMainWidget(&hello)
Signaux et slots
Un signal est mis vers le monde extrieur
- par un objet (QObject, QWidget...) - quand il change d'tat - on nindique pas qui il sadresse
Signaux et slots
Modularit, exibilit
- le mme signal peut tre connect plusieurs slots - plusieurs signaux peuvent tre connects un mme slot
Connexion
Typage fort
- les types des paramtres des signaux et des slots doivent tre les mmes - un slot peut avoir moins de paramtres qu'un signal
QObject::connect( &quitBtn, SIGNAL(clicked( )), &app, SLOT(quit( )) );
De plus
- l'metteur n'a pas besoin de connatre le ou les rcepteur(s) - il ne sait pas si le signal est reu - le rcepteur n'a pas non plus besoin de connatre l'metteur => vers modle multi-agents ou programmation par composants
QObject::connect( &x, SIGNAL(balanceChanged(int)), &y, SLOT(setBalance(int)) ); QObject::connect( &x, SIGNAL(balanceChanged(int)), &app, SLOT(quit()) );
Remarques
- aspect central de Qt - diffre de l'habituel mcanisme des callbacks ou Listeners
Avantages / inconvnients
- SLOT et SIGNAL sont des macros = > phase de prcompilation
Dclaration de slot
Dans le chier header (.h)
class BankAccount : public QObject { Q_OBJECT private: int curBalance; public: BankAccount( ) { curBalance = 0; } int getBalance( ) const { return curBalance; } public slots: void setBalance( int newBalance ); signals: void balanceChanged( int newBalance ); };
Dnition de slot
Dans le chier source de l'implmentation (.cpp)
void BankAccount::setBalance(int newBalance) { if ( newBalance != curBalance ) { curBalance = newBalance; emit balanceChanged(curBalance); } }
- mot-cl emit pour prcompilateur - provoque l'mission du signal balanceChanged avec la nouvelle valeur de curBalance
- sous classe de QObject - mot-cls Q_OBJECT, slots et signals pour prcompilateur - signaux pas implments, slots doivent tre implments
Dnition de slot
Dans le chier source de l'implmentation (.cpp)
void BankAccount::setBalance(int newBalance) { if ( newBalance != curBalance ) { curBalance = newBalance; emit balanceChanged(curBalance); } }
Connexion
Connexion simple
BankAccount x, y; QObject::connect( &x, SIGNAL(balanceChanged(int)), &y, SLOT(setBalance(int)) ); x.setBalance( 2450 );
- x est mis 2450 - le signal balanceChanged() est mis - il est reu par le slot setBalance() de y - y est mis 2450
- mot-cl emit pour prcompilateur - provoque l'mission du signal balanceChanged avec la nouvelle valeur de curBalance - Attention : vrier que la valeur a effectivement chang pour viter les boucles innies !
Connexion
Connexion dans les deux sens
QObject::connect( &x, SIGNAL(balanceChanged(int)), &y, SLOT(setBalance(int)) ); QObject::connect( &y, SIGNAL(balanceChanged(int)), &x, SLOT(setBalance(int)) ); x.setBalance( 2450 );
Compilation
Meta Object Compiler (MOC)
- pr-processeur C++ - gnre du code supplmentaire (tables de signaux /slots) - permet aussi de rcuprer le nom de la classe et de faire des test d'hritage - attention: ne pas oublier le mot-cl Q_OBJECT
Utilisation de qmake
- dans le rpertoire contenant les chiers sources faire: qmake -project qmake make // cre le chier xxx.pro (dcrit le projet) // cre le chier Makele (ou quivalent si IDE) // cre les chiers moc (un par chier ayant des slots), // et les chiers binaires (*.o et excutable
Fentre principale
(QMainWindow)
barre de menu barre doutils barre de statut zone centrale
Fentre principale
Dans le constr. de la classe lle de QMainWindow // menuBar() est une methode de QMainWindow QMenuBar* menubar = menuBar( ); QMenu* lemenu = menubar->addMenu( tr("&File") ); // new.png est un chier qui sera spci dans une chier de ressources .qrc QAction* new_action = new QAction( QIcon(":/images/new.png"), tr("&New..."), this ); new_action->setShortcut( tr("Ctrl+N") ); new_action->setToolTip( tr("New le") ); new_action->setStatusTip( tr("New le") ); lemenu->addAction( new_action ); // acclrateur clavier // bulle daide // barre de statut // rajouter laction au menu droulant
Usage
- crer une sous-classe de QMainWindow - crer ses enfants dans son constructeur
// connecter le signal un slot de this connect( new_action, SIGNAL(triggered( )), this, SLOT(open( )) );
Fentre principale
Actions
- les actions peuvent sajouter la fois dans les menus et les toolbars
QToolBar* toolbar = addToolBar( tr("File") ); toolbar->addAction(new_action);
Botes de dialogue
QFileDialog, QMessageBox
Widget central
QTextEdit* text = new QTextEdit(this); setCentralWidget( text );
tr( )
- permet de traduire le texte (localisation) - ( suivre)
QString
Codage Unicode 16 bits
- Suite de QChars 1 caractre = 1 QChar de 16 bits (cas usuel) 1 caractre = 2 QChars de 16 bits (pour valeurs > 65535) - Conversions dune QString : toAscii( ) : ASCII 8 bits
Solution simplie
QString leName = QFileDialog::getOpenFileName( this,
toLatin1( ) : Latin-1 (ISO 8859-1) 8 bits toUtf8( ) : UTF-8 Unicode multibyte (1 caractre = 1 4 octets) toLocal8Bit( ) : codage local 8 bits - qPrintable ( const QString & str ) quivalent : str.toLocal8Bit( ).constData( )
QFile
QFile
- lecture, criture de chiers - exemples :
QFile le( leName ); if ( le.open( QIODevice::ReadOnly | QIODevice::Text) ) ...; if ( le.open( QIODevice::WriteOnly ) ) ...;
QTextStream
QTextStream
- lecture ou criture de texte depuis un QFile :
QTextStream stream( &le );
- mais aussi :
QString readLine( maxlen = 0 ); QString readAll( ); // pratique mais nutiliser que pour des petits chiers
- codecs :
setCodec( codec ), setAutoDetectUnicode( bool );
Layout
Problmes
- internationalisation - retaillage - complexit du code
Layout : exemple
QVBoxLayout *v_layout = new QVBoxLayout( ); v_layout->addWidget( new QPushButton( "OK" ) ); v_layout->addWidget( new QPushButton( "Cancel" ) ); v_layout->addStretch( 1 ); 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( ); topLevelBox->addWidget( new QLabel( "Select a country", this ) ); topLevelBox->addLayout( h_layout ); window->setLayout( top_layout ); window->show( );
QFormLayout
Styles
Emulation du "Look and Feel"
- Look and feel simul et paramtrable (comme Swing) - rapidit, exibilit, extensibilit, - pas restreint un "dnominateur commun"
Ressources
Fichier source
QAction* newAct = new QAction( QIcon(":/images/new.png"), tr("&New..."), this ); newAct->setShortcut( tr("Ctrl+N") ); // : signie: relatif au programme // tr( ) pour ventuelle traduction // lacclrateur clavier peut tre traduit
QStyle
- QApplication::setStyle( new MyCustomStyle );
Fichier .qrc
- cr la main ou par QtCreator
<!DOCTYPE RCC><RCC version="1.0"> <qresource> <file>images/copy.png</file> <file>images/cut.png</file> <file>images/new.png</file> <file>images/open.png</file> <file>images/paste.png</file> <file>images/save.png</file> </qresource> </RCC>
Graphique 2D
Deux modles
- QPainter : modle fonctionnel - Graphics View : modle objet
Graphique 2D
Deux modles
- QPainter : modle fonctionnel - Graphics View : modle objet
QGraphicsScene scene; QGraphicsRectItem *rect = scene.addRect( QRectF(0,0,100,100) ); QGraphicsItem *item = scene.itemAt(50, 50); // item == rect ..... QGraphicsView view( &scene ); view.show( );
QPainter
- modle graphique volu (rotations, indpendance / pilote ...) - dessin par appel de mthodes - similaire Graphics2D en Java - exemple : QPainter painter( this ); // this est un widget painter.setPen( QPen(red, 2, DashLine) ); painter.drawRect( 25, 15, 120, 60 ); - section ddie dans la suite du cours
Graphics View
- graphique structur reprsentation objet du dessin rafraichissement automatique, fonctions de picking ... - vues dun graphe de scne : QGraphicsScene QGraphicsView QGraphicsItem, etc.
Graphique 2D
QIcon
QPushButton *button = new QPushButton( "&Find Address", parent ); button->setIcon( QIcon(":/images/new.png")) ); - cf chiers de ressources .qrc
Graphique 3D
3D
- via OpenGL sur QGLWidget - 3 mthodes rednir :
virtual void initializeGL() virtual void paintGL() virtual void resizeGL(int w, int h)
QImage, QPixmap
- QImage: optimis accs/manipulation des pixels - QPixmap, QBitmap : optimiss pour afchage lcran - ( suivre)
OpenGL : main
#include <qapplication.h> #include <qslider.h> #include <qvbox.h> #include "box3d.h" void createSlider( QWidget * parent, Box3D * box3d, const char * slot) // cf. le type de slot ! { QSlider *slider = new QSlider(0, 360, 60, 0, QSlider::Horizontal, parent); slider->setTickmarks(QSlider::Below); QObject::connect( slider, SIGNAL(valueChanged(int)), box3d, slot);
OpenGL : main
int main(int argc, char **argv) { QApplication::setColorSpec(QApplication::CustomColor); QApplication app(argc, argv); if (!QGLFormat::hasOpenGL( )) qFatal("This system has no OpenGL support"); QVBox * parent = new QVBox( ); parent->setCaption("OpenGL Box"); parent->setMargin(11); parent->setSpacing(6); Box3D *box3d = new Box3D(parent); createSlider( parent, box3d, SLOT(setRotationX(int)) ); createSlider( parent, box3d, SLOT(setRotationY(int)) ); createSlider( parent, box3d, SLOT(setRotationZ(int)) ); parent->resize( 250, 250 ); parent->show( ); return app.exec( ); }
. . . .
Dessin interactif
Illustr avec Qt
Rafrachissement
Le widget est repeint
- Lorsque une fentre passe au dessus - Lorsque lon dplace le composant - Lorsque lon le lui demande explicitement
vnements
- lorsquon relche un bouton - lorsquon double-clique - lorsquon dplace la souris - en appuyant ou pas sur un bouton (mouseTracking)
void MyWidget::paintEvent(QPaintEvent* e) { ! QWidget::paintEvent(e); // effectue le comportement standard (afcher le fond...) ! QPainter painter(this); // cre un Painter pour linstance de MyWidget ! painter.drawLine(50, 10, 100, 20); }
Synthse
mousePressEvent(QMouseEvent* e)
! ! }
QMouseEvent : permet de rcuprer - le bouton qui a dclench lvnement - ltat des autres boutons (cliqus ou non) - la position de la souris (globale et locale)
Dessin
QPainter
Attributs
- setPen( ) : lignes et contours - setBrush( ) : remplissage - setFont( ) : texte - setTransform( ), etc. : transformations afnes - setClipRect/Path/Region( ) : clipping (dcoupage) - setCompositionMode( ) : composition
QPainter : outil de dessin QPaintDevice : objet sur lequel on peut dessiner QPaintEngine : moteur de rendu On peut dessiner dans tout ce qui hrite de QPaintDevice
QPainter
Lignes et contours
- drawPoint(), drawPoints() - drawLine(), drawLines() - drawRect(), drawRects() - drawArc(), drawEllipse() - drawPolygon(), drawPolyline(), etc... - drawPath() : chemin complexe
QPainter
Classes utiles
- entiers: QPoint, QLine, QRect, QPolygon - ottants: QPointF, QLineF, ... - chemin complexe: QPainterPath - zone dafchage: QRegion
Remplissage
- llRect(), llPath()
Divers
- drawText() - drawPixmap(), drawImage(), drawPicture() - etc.
Pinceau: QPen
Attributs
- style : type de ligne - width : paisseur (0 = cosmetique) - brush : attributs du pinceau (couleur...) - capStyle : terminaisons - joinStyle : jointures Cap Style Qt::PenStyle
Pinceau: QPen
Exemple
QPen pen; // creates a default pen
Qt::PenStyle
Cap Style
// dans PaintEvent() QPainter painter(this); painter.setPen(pen);
Join Style
Join Style
Remplissage: QBrush
Attributs
- style - color - gradient - texture Qt::BrushStyle
Remplissage: QBrush
Attributs
- style - color - gradient - texture
QColor
- modles RGB, HSV or CMYK - composante alpha (transparence) : alpha blending - couleurs prdnies: Qt::GlobalColor
Qt::GlobalColor
Remplissage: gradients
Type
- lineaire - radial - conique QLinearGradient QRadialGradient
Composition
Modes de composition
- oprateurs de Porter Duff - exemples : SourceOver : dfaut, permet alpha blending Source = SourceOver avec source opaque - diverses limitations selon implmentation et Paint Device
QLinearGradient gradient(QPointF(0, 0), QPointF(100, 100)); gradient.setColorAt(0, Qt::white); gradient.setColorAt(1, Qt::blue); QBrush brush(gradient);
QConicalGradient
Mthode: QPainter::setCompositionMode( )
rptition: setSpread()
Dcoupage (clipping)
Dcoupage
- selon un rectangle, une rgion ou un path - QPainter::setClipping(), setClipRect(), setClipRegion(), setClipPath()
Transformations afnes
Transformations
- translate() - rotate() - scale()
Dmo !
QRegion
- united(), intersected(), subtracted(), xored()
QRegion r1(QRect(100, 100, 200, 80), QRegion::Ellipse); QRegion r2(QRect(100, 120, 90, 30)); QRegion r3 = r1.intersected(r2); QPainter painter(this); painter.setClipRegion(r3); ...etc... // paint clipped graphics // r1: elliptic region // r2: rectangular region // r3: intersection
- shear() - setTransform()
QPainter painter( this ); painter.setRenderHint( QPainter::Antialiasing ); painter.translate( width( ) / 2, height( ) / 2 ); painter.scale( side/200.0, side/200.0 ); painter.save( ); // empile ltat courant painter.rotate( 30.0 * ((time.hour() + time.minute() / 60.0)) ); painter.drawConvexPolygon( hourHand, 3 ); painter.restore( ); // dpile
Hints et Antialiasing
Render hints
- hint = option de rendu effet non garanti dpend de limplmentation et du matriel - QPainter::setRenderingHints()
Antialiasing et cordonnes
Epaisseurs impaire
- pixels dessins droite et en dessous Note
QRect::right() = left() + width() -1 QRect::bottom() = top() + height() -1 Mieux : QRectF (en ottant)
Dessin anti-alias
- pixels rpartis autour de la ligne idale
Anti-aliasing
- viter leffet descalier QPainter::Antialiasing
QPainter painter(this); painter.setRenderHint(QPainter::Antialiasing); painter.setPen(Qt::darkGreen); painter.drawLine(2, 7, 6, 1);
QPainterPath
QPainterPath
- gure compose dune suite arbitraire de lignes et courbes afche par: QPainter::drawPath() peut aussi servir pour remplissage, prolage, dcoupage
QPainterPath
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 );
Mthodes
- dplacements: moveTo(), arcMoveTo() - dessin: lineTo(), arcTo() - courbes de Bezier: quadTo(), cubicTo() - addRect(), addEllipse(), addPolygon(), addPath() ... - addText() - translate(), union, addition, soustraction... - et dautres encore ...
Dmo !
QPainterPath
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.llRect(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);
Surfaces dafchage
Qt::OddEvenFill (dfaut)
Qt::WindingFill
Images
Types dimages
- QImage: optimis pour E/S et accs/manipulation des pixels QPixmap, QBitmap : optimiss pour afchage lcran - QPicture: pour enregistrer et rejouer les commandes dun QPainter - dans tous les cas : on peut dessiner dedans avec un QPainter
QPicture
Enregistrer et rejouer les commandes dun QPainter
- Enregistrer :
QPicture picture; QPainter painter; painter.begin( &picture ); painter.drawEllipse( 10,20, 80,70 ); painter.end( ); picture.save( "drawing.pic" ); // paint in picture // draw an ellipse // painting done // save picture
OpenGL
- QGLWidget QGLPixelBuffer QGLFramebufferObject QSvgWidget
- Rejouer :
QPicture picture; picture.load( "drawing.pic" ); QPainter painter; painter.begin( &myImage ); painter.drawPicture( 0, 0, picture ); painter.end( ); // load picture // paint in myImage // draw the picture at (0,0) // painting done
Impression
- QPrinter
Picking
Picking avec QRect, QREctF
- intersects() - contains()
Picking / Interaction
Exemple
- teste si la souris est dans le rectangle quand on appuie sur le bouton de la souris - met jour la position du rectangle pour quil soit centr
QRect rect; // variable dinstance de mon Widget de dessin
Retourne lintersection
- QPainterPath intersected(const QPainterPath & path)
void mousePressEvent(QMouseEvent* e) { if (rect.contains( e->pos() )) { rect.moveCenter( e->pos() ); update( ); } ... void paintEvent(QPaintEvent* e ) { QPainter painter( this ); ..... // specier attributs graphiques painter.drawRect( rect ); }
Performance de lafchage
Problmes classiques :
- Flicking - Tearing - Lag
Flicking
Flicking
- scintillement de lafchage - car loeil peroit les images intermdiaires - exemple : rafraichir cette page tout effacer (peindre en blanc) puis tout redessiner (effet plus fort si le fond est sombre)
source: AnandTech
Double buffering
Double buffering
- solution au icking : dessin dans back buffer recopie dans front buffer - par dfaut avec Qt4
Double buffering
Page ipping
- implmentation frquente du double buffering - pas de recopie des pixels, on change juste de buffer - vite le tearing si synchro avec lafchage (vsync)
src: Oracle/JavaSE
Triple buffering
Triple buffering
- comme double buffering mais plus rapide - un back buffer est toujours disponible mme avec synchro
Performance de lafchage
Latence
- lafchage ne suit pas linteraction
Remdes
- rduire la quantit dlments rafcher clipping : mthodes rect() et region() de QPaintEvent - sauver le dessin dans une image et rafcher en bloc double buffering logiciel, composition de buffer + dessin - afchage en mode XOR source: AnandTech
XOR
Principe
- afchage en mode XOR trs efcace pour dplacements interactifs
Machines tats
et modes dinteraction
Problmes
- couleurs alatoires - plus disponible avec Qt4
Exemple Java Graphics : - setColor(Color c1) - setPaintMode() : dessine avec c1 - setXORMode(Color c2) : change c1 et c2
Problme :
- pas compatible avec la gestion vnementielle
Machines tats
Une solution approprie pour maintenir ltat !
- simple et efcace pour modliser les comportements - vite les spaghettis de callbacks et la multiplication des variables dtat et des erreurs ! - passage facile dune reprsentation visuelle au code source - divers outils, UML, QState
vnements
Etat
Etat de dpart
Etat nal
Machines tats
Transitions
- Reprsentes par des arcs avec un label : Evnement / Action si on est dans ltat A et cet vnement se produit cette action est effectue puis on passe dans ltat B Mouse_Dn / Draw_Line()
Machines tats
Retour notre ligne lastique
Accept the press for endpoint p1; P2 = P1; Draw line P1-P2; Repeat
A
- Remarque : les actions sont parfois sur les tats (cas de Qt) quand on entre dans ltat quand on sort de ltat
Machines tats
Move / B Press / A Release / C
Machines tats
Autre exemple : bouton
Release / E Enter / C Press-inside / A Leave / B Release / D
Accept the press for endpoint p1; P2 = P1; A Draw line P1-P2; Repeat Erase line P1-P2; B P2 = current_position(); Draw line P1-P2; Until release event; C Act on line input;
A: B: C: D: E:
Machines tats
- Evnements : de plus ou moins haut niveau peuvent aussi tre des timeouts - Gardes condition supplmentaire notation : prdicat : vnement / action exemple: button.enabled: press-inside / A - Implmentation compatible avec la boucle de gestion des vnements
state = start_state; for ( ; ; ) { raw_evt = wait_for_event(); evt = transform_event(raw_evt); state = fsm_transition(state, evt); }
Machines tats
Implmentation en dur
Move / B
State fsm_transition(state, event) { switch(state) { case 1: switch(event.kind) { case MouseMove: action_B(); state = 1; case MouseRelease: action_C() state = 2;
Press / A
Release / C
state = start_state; for ( ; ; ) { raw_evt = wait_for_event(); evt = transform_event(raw_evt); state = fsm_transition(state, evt); } }
Machines tats
Utilisation
- prfrer lutilisation doutils existants - bass sur des tables dtats et de transitions
Qt State Machine
Qt : State Machine Framework
- modle hierarchique : StateCharts - bass sur SCXML - permet : groupes dtats (hirarchies) tats parallles (pour viter lexplosion combinatoire) tats historiques (pour sauver et restaurer ltat courant) dinjecter ses propres vnement, etc. - sert galement pour faire des animations
Java
- SwingStates (C. Appert) - http://swingstates.sourceforge.net/ - classe Canvas qui facilite le dessin interactif - exemples dinteractions avances
Etats parallles
Pour viter lexplosion combinatoire
QState *s1 = new QState( QState::ParallelStates ); // s11 and s12 will be entered in parallel QState *s11 = new QState(s1); QState *s12 = new QState(s1);
Types de transitions
Pour les signaux : QSignalTransition
s1->addTransition(button, SIGNAL(clicked( )), s2);
void addTrans(QState* from, QState* to, // une petite fonction utile QObject* object, QEvent::Type type, Qt::MouseButton button) { QMouseEventTransition* trans = new QMouseEventTransition(object, type, button, from); trans->setTargetState(to); from->addTransition(trans); }
Filtres de transitions
Pour ajouter des gardes ou des conditions complexes Ou toute autre action utile... Exemple :
// transitions :
addTrans(s1, s2, canvas, QEvent::MouseButtonPress, Qt::LeftButton); addTrans(s2, s2, canvas, QEvent::MouseMove, Qt::NoButton); addTrans(s2, s1, canvas, QEvent::MouseButtonRelease, Qt::LeftButton);
Filtres de transitions
Une solution : - crer une sous-classe de QMouseEventTransition qui rednit eventTest( ) - pour sauvegarder currentPos, la position de la souris
class MouseEventTrans : public QMouseEventTransition { Canvas* canvas; // canvas a une variable currentPos public: MouseEventTrans(Canvas* object, QEvent::Type type, Qt::MouseButton button, QState * srcState) : QMouseEventTransition(object, type, button, srcState), canvas(object) { } bool eventTest (QEvent * e) { if ( ! QMouseEventTransition::eventTest(e) ) return false;
// quand on sort de s1
// quand on entre dans s2
QStateMachine::WrappedEvent* we = static_cast<QStateMachine::WrappedEvent*>(e); QEvent* realEvent = we->event( ); // le vrai vnment souris switch (realEvent->type( )) { case QEvent::MouseMove: canvas->currentPos = static_cast<QMouseEvent*>(realEvent)->pos( ); // sauver la position souris break; .... etc... } return true; // true signie que lvnement dclenche la transition (sinon il est ignor) } };
Problme : - addLine( ) et changeLine( ) nont pas dargument - comment rcuprer la position de la souris ?
Un bon conseil
Faire au plus simple !
- utiliser les groupes (hirarchies et paralllisme) pour simplier les schmas - rappel : les tats enfants hritent des transitions des tats parents
Transitions et proprits
assignProperty
s1->assignProperty( label, "text", "In state s1" ); s1->assignProperty( button, "geometry", QRectF(0, 0, 50, 50) );
Exemple
- quatre radio boutons exclusifs
mauvaise solution
bonne solution
Syntaxe dinteraction
Exemples de syntaxe
- objet verbe mettre du texte en orange - (objet)* verbe dtruire plusieurs chiers - (objet)* verbe objet dplacer plusieurs chiers - verbe objet tracer un seul trait - verbe (objets)* tracer plusieurs traits de suite - verbe objet ou (objet)* verbe le surligneur de Word
Modes dinteraction
Modes spatiaux
- leffet dune action dpend de lendroit o elle est effectue boutons, menus... - avantage : visibilit dcouverte, mmorisation
Modes temporels
- leffet dune action dpend du moment o elle est effectue palettes doutils de dessin bote de dialogue modale - gnralement incontournables pour crer de nouveaux objets - inconvnient : visibilit dcouverte, erreurs (quel est ltat courant ?)
Modes dinteraction
Mode temporel
- actions interprtes dune manire spcique tant que le mode est activ mode tracer plusieurs traits - syntaxe : verbe (objets)*
Modes dinteraction
Modieurs
- modient le comportement usuel - touches Control, Shift, Alt... - boutons de la souris gauche : slectionner, dplacer, activer droite : menu contextuel - multitouch 1 doigt : comme la souris 2 doigts : dler la vue, zoomer, pivoter
Modes dinteraction
Cas des crans tactiles passifs
- pas de claviers (en gnral) => pas de modieurs ni de raccourcis clavier - pas de boutons de la souris ni de mode hover => moins dtats interactionnels, ambiguits - alternatives multitouch gestes 3D (acclromtre, gyroscope, magntomtre...)
Qt Designer
Qt Designer
Fichiers
calculator.pro calculatorform.ui calculator.h calculator.cpp main.cpp
Qt Designer
fichiers gnres par QtCreator main.cpp
#include "calculator.h" int main (int argc, char *argv[]) { QApplication app(argc, argv); Calculator widget; .... widget.show(); return app.exec(); }
calculatorform.ui
fichier XML
calculator.pro
TEMPLATE = app FORMS = calculatorform.ui SOURCES = main.cpp HEADERS = calculator.h
Exemple
vido et code .ui
Qt Designer
#include "ui_calculatorform.h" class Calculator : public QWidget { Q_OBJECT public: Calculator(QWidget *parent =0); private : Ui::CalculatorForm * ui; };
Qt Designer
Comment afficher le rsultat du calcul dans le Qlabel ?
calculator.h
calculator.cpp
#include "calculator.h Calculator::Calculator(Qwidget *parent) : QWidget(parent) { ui->setupUi(this); }
#include "ui_calculatorform.h" class Calculator : public QWidget { Q_OBJECT public: Calculator(QWidget *parent =0); private : Ui::CalculatorForm * ui; private slots : void on_spinBox1_valueChanged(int value); void on_spinBox2_valueChanged(int value); }; #include "calculator.h Calculator::Calculator(Qwidget *parent) : QWidget(parent) { ui->setupUi(this); } void Calculator::on_spinBox1_valueChanged(int val) { QString res = QString::number(val); // ou: QString res = QString::number( ui->spinBox1->value() ); ui->label3->setText(res); } // label3 : nom du widget dans QtCreator
Qt Designer
Auto-connect on peut lier les signaux des objets crs interactivement avec nimporte quel slot : par auto-connexion void on_spinBox1_valueChanged(int) via le mode Edition Signaux/Slots de QtCreator
Variante
Mme principe mais en utilisant lhritage multiple
#include "ui_calculatorform.h" Class Calculator : public QWidget, private Ui::CalculatorForm { Q_OBJECT public: Calculator(Qwidget *parent =0); }; Calculator::Calculator(Qwidget *parent) : Qwidget(parent) { setupUi(this); // au lieu de ui->setupUi(this) } void Calculator::on_spinBox1_valueChanged(int val) { QString res = QString::number(val); label3->setText(res); } // au lieu de : ui->label3->setText(res); }
Chargement dynamique
#include <QtUiTools> Calculator::Calculator(QWidget *parent) : QWidget(parent) { QUiLoader loader; QFile file(":/forms/calculatorform.ui"); file.open(QFile::ReadOnly); QWidget *formWidget = loader.load(&file, this); file.close();
class Calculator : public QWidget { Q_OBJECT public: Calculator(QWidget *parent = 0); private: QSpinBox *ui_spinBox1; QSpinBox *ui_spinBox2; QLabel *ui_label1; }; ..... ui_spinBox1 = qFindChild<QSpinBox*>(this, "spinBox1"); ui_spinBox2 = qFindChild<QSpinBox*>(this, "spinBox2"); ui_label1 = qFindChild<QLabel*>(this, "label1");