Introduction à Qt Gilles Bailly

La page est créée Anne Raymond
 
CONTINUER À LIRE
Introduction à Qt Gilles Bailly
Introduction à Qt

     Gilles Bailly
gilles.bailly@upmc.fr
Introduction à Qt Gilles Bailly
Crédits
• Eric Lecolinet

                             2
Introduction à Qt Gilles Bailly
• hci.isir.upmc.fr/ihm-androide/

                                   3
Introduction à Qt Gilles Bailly
http://pyqt.sourceforge.net/Docs/
         PyQt5/index.html

                                4
Introduction à Qt Gilles Bailly
Introduction

1
Introduction à Qt Gilles Bailly
What ?
Librairie graphique écrite en C++ par la société TrollTech.
 – Mécanisme pour interagir :
   avec l’utilisateur (bouton, liste déroulante, ..)
   avec le système (OpenGl, Xml, SQL, sockets, plugin…)

Multi-Plateforme
 – Windows | Mac | Linux
 – Android | iOS | WinRT | BlackBerry* | SailFish
 – Embedded Linux | Embedded Android | Windows Embedded

Gratuit (GPL),
 -   mais dispose aussi d’une licence commerciale

Approche :
 – Ecrire une fois, compiler n’importe où
Introduction à Qt Gilles Bailly
7
Introduction à Qt Gilles Bailly
Historique
• 1988 : Haavard & Eirik ont l’idée de créer une librairie
  graphique orientée objet
• 1993 : Le noyau est terminé et ont pour objectif « The world’s
  best C++ GUI framework »
   – Nom Qt, signaux et slots
• 2001 : Qt 3.0, 500 000 lignes de codes, Linux, Windows, Mac.
• 2008 : Qt 4.5 (racheté par Nokia; 250 employés)
   – la plateforme Symbian
• 2009 : Qt 4.6 : animation; GraphicScene; machine à état;
  gestures
• 2011 : Qt est racheté par Digia
   – objectif : Android, iOS et Windows 8
• 2012 : Qt 5.0 : Qt Quick (javascript)
• 2016 : Qt compagny
Introduction à Qt Gilles Bailly
Why?
•   Performance (C++)
•   Relativement Simple
•   Gratuit (GPL) et code source
•   Nombreux outils
    –   Générateur d’interface : Qt Designer
    –   Internationalisation : Qt Linguist
                                               Qt creator
    –   Documentation : Qt Assistant
    –   Examples : Qt Examples
    –   Programmation : Qt Creator (eclipse)
• Multi-Plateformes
    – Look and feel simulé

                                               Designer
Introduction à Qt Gilles Bailly
10
Aujourd'hui
• Utilisateurs de Qt :
   – Adobe Photoshop, Autodesk Maya, Google Earth, Skype, Spotify, VLC
     media player

• Bindings (java, python, c#)
12
13
14
Aujourd'hui

Qt Widgets     Qt Graphics view   Qt quick /QML

                                           15
Aujourd'hui

                    v.s.

  Qt Widgets                    Qt Graphics view

▪ Widgets cannot be scaled or rotated,
▪ Widgets can only appear once on the desktop,
  but several views can observe one graphicsitem.
▪ Widgets express their geometries in pixels, graphics items use logical units.
  (…int vs. double)
▪ Widgets support tons of features that graphics items don’t understand.
▪ Widgets understand layouts,
▪ 4000000 widgets don’t work that well, but 4000000 items works perfectly. 16
17
Aujourd'hui

                       v.s.

    Qt Widgets                       Qt quick/QML

QML is based on JSON (Language); QtQuick (library)
Widgets are more mature, flexible and provide rich features Language déclaratif
Qt Quick focuses on animation and transition
Qt Quick is mainly for mobile devices (today)
Qt Quick will (maybe) remplace Widgets tomorrow
Qt Quick is maybe easier to use for designers
                                                                                  18
19
20
Aujourd'hui

                     v.s.

    QGraphicsView                 Qt quick/QML

Qt Quick Graphics engine only works with OpenGL   Language déclaratif
Drawing complex shapes easier with QGraphicView
Qt Quick: QML & Javascript
QML is more compatible with Widget

                                                                        21
Qt (QML) vs. HTML 5

                      22
Objectifs
Introduction
   – Signaux et slots
   – Les principales classes Qt

Graphisme avancé
   – Création de vos propres widgets
   – Programmation événementielle
   – Notion avancée de graphisme avec Qt

Quelques autres notions avancées
   –   Machine à états
   –   Gestes
   –   Animation
   –   Qt Designer
                                           Au delà de Qt …
Syntaxe

                   Syntaxe C                              Syntaxe Python

int factorielle(int n) {                  def factorielle(n):
    if (n < 2) {                              if n < 2:
        return 1;                                 return 1
    } else {                                  else:
        return n * factorielle(n - 1);            return n * factorielle(n - 1)
    }
}

                           Attention aux tabulations !!!
Typage dynamique fort

int a = 4

a=4
type(a)           

a = 4.1
type(a)
Classes

class Voiture:             ➡   Déclaration d’une classe
   #commentaire
   nbRoues=4

   def __init__(self,marque,couleur):          ➡ Déclaration d’un constructeur
      self.couleur=couleur     ➡ Déclaration d’une variable d’instance
      self.marque=marque       ➡ Déclaration d’une variable d’instance

def main():
                ➡ Déclaration conventionnelle d’une méthode main()
   audirouge = Voiture('audi','rouge')
   print(audirouge.couleur)

if __name__ == "__main__":
    main(sys.argv)                             ➡    Appel automatique Main
Mes premiers pas avec Qt

2
       "Hello world"
28
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
import sys

def main(args) :
     app = QApplication(args)
     button = QPushButton("Hello World !", None)
     button.resize(100,30)
     button.show()
     app.exec_()

if __name__ == "__main__" :
      main(sys.argv)
                                               29
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
import sys

def main(args) :
     app = QApplication(args)
     widget = QWidget(None)
     widget.resize(150,90)
     button = QPushButton("Hello World !", widget)
     button.resize(100,30)
     widget.show()
     app.exec_()

if __name__ == "__main__" :
      main(sys.argv)
                                                30
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
import sys

def main(args) :
     app = QApplication(args)
     widget = QWidget(None)
     widget.resize(150,90)
     button = QPushButton("Hello World !", widget)
     button.resize(100,30)
     widget.show()
     button.clicked.connect(app.quit)
     app.exec_()

if __name__ == "__main__" :
      main(sys.argv)                            31
Signaux et Slots

3
Problématique
• Comment
  – à partir d’un « clic sur un bouton »
  – Je peux éxécuter la partie correspondant à la logique de mon
    application ? (ex: fermer l’application)

• Solutions
  – MFC (introduit un langage au dessus de C++)
  – Java (utilise des listeners)
  – Qt (utilise principalement des signaux et slots)
Connecter Signaux et Slots
class QSlider(QObject):                  class QLCDNumber(QObject):
  ….
  def mousePressEvent(self):                def display(num):
   self.valueChanged.emit(value)                m_value = num;
   …                                            …

   slider = QSlider(None)                          lcd = QLCDNumber(none)

                               42   connexion        42

                                                          Slot implémenté
           Signal émis

                 slider.valueChanged.connect(lcd.display)
Une classe avec des signaux et des slots

          class MyClass(QObject):

              mySignal = pyqtSignal(int)

              def mySlot( self, num ):
                  blabla

• Sous class de QObject
• Les signaux sont pas implémentés
• Les slots doivent êtres implémentés
Une classe avec des signaux et des slots

          class MyClass(QObject):

             mySignal = pyqtSignal(int)

             def __init__(self, parent =None):
                 super(MyClass, self).__init__(parent)

             def mySlot( num ):
                 blabla

• Sous class de QObject
• Les signaux sont pas implémentés
• Les slots doivent êtres implémentés
Signaux et Slots

• Modularité, flexibilité
  – Connecter plusieurs signaux à un slot
  – Connecter un signal à plusieurs slots
• Philosophie
  –   L’émetteur n’a pas besoin de connaître le(s) récepteur(s)
  –   L’émetteur ne sait pas si le signal a été reçu
  –   Le récepteur ne connaît pas non plus l’émetteur
  –   Programmation par composant (indépendant, réutilisable)
• Sécurité, typage fort (en C++)
  – Les types des paramètres doivent être les mêmes
  – Un slot peut avoir moins de paramètres qu’un signal
transfert d’argent entre deux banques

      BANK 1              BANK 2

      BANK 1              BANK 2

                                   38
transfert d’argent entre deux banques
class BankAccount (QObject):
  balance = 0
  name = “"

  balanceChanged = pyqtSignal(int)
                                                      Signal
  def setBalance(self, newValue):
   self.balance = newValue                            Slot
   self.balanceChanged.emit( self.balance )

def main(args):
  account1 = BankAccount()
  account1.setName( “account1” )

  account2 = BankAccount()
  account2.setName( “account2” )

  account1.balancedChanged.connect( account2.setBalance )
  account2.balancedChanged.connect( account1.setBalance )      Connexion

if __name__ == “__main__”:
   main(sys.argv)
                                                      Problème?
transfert d’argent entre deux banques

 def setBalance(self, newValue):
   if self.balance != newValue:
      self.balance = newValue
      self.balanceChanged.emit( self.balance )

                                     account1
Un peu plus loin…

           class MyClass(QObject):

               mySignal = pyqtSignal(int)

               def __init__(self, parent =None):
                   super(MyClass, self).__init__(parent)

               @pyqtSlot(int)               parfois nécessaire
               def mySlot( num ):
                   blabla

• Sous class de QObject
• Les signaux sont pas implémentés
• Les slots doivent êtres implémentés
    • peuvent être décorés de @pyqtSlot
    réduit la quantité de mémoire / est plus rapide
    parfois utile pour les “auto-connect"
42
Encore un peu plus loin
• les auto-connect
    class MyClass(QObject):

        def __init__(self, parent =None):
            self.buttonA = QPushButton(‘button 1’, self)
            self.buttonA.setObjectName('buttonA)
            self.spinBox = QSpinBox(self)
            self.spinBox.setObjectName('mySpinBox')
            ….
            QMetaObject.connectSlotsByName(self)

        def on_buttonA_clicked(self):
            blabla

      @pyqtSlot(int)
       def on_mySpinBox_valueChanged(self, arg):
           blabla
                                                           43
Questions
Comment connecter un signal à un slot ?
 • EmetteurObj..connect ( Recepteur. )

Quel code pour déclarer / implémenter un slot ?
 • rien de particulier (mais on peut rajouter @pyqtSlot() )

Est ce qu’un slot peut retourner une valeur ?
 • Oui

Quel code pour déclarer / implémenter un signal ?
 • mySignal = pyqtSignal()
Ce qui se cache derrière
• en C++ c’est plus compliqué

                                45
Les principaux widgets
Modules
•   QtCore
•   QtWidgets
•   QtBluetooth
•   QtOpenGL
•   QtSript/QtScriptTools
•   QtSql
•   QtSvg
•   QtWebKit
•   QtXml/QtXmlPatterns
•   QtMultimedia
•   QtSensors
•   …
QtCore
• QObject
• Type de base : QChar, QDate, QString, QStringList,
  Qtime,…
• File systems : QDir,QFile,…
• Container : QList, Qmap, Qpair, QSet, QVector,…
• Graphique : QLine, Qpoint, QRect, QSize …
• Thread : QThread, Qmutex, Qsemaphore, …
• Autres : QTimer, QTimeLine, …
QString

Codage Unicode 16 bits
  - Suite de QChars
        • 1 caractère = 1 QChar de 16 bits (cas usuel)
        • 1 caractère = 2 QChars de 16 bits (pour valeurs > 65535)

  - Conversions d’une QString :
        • toAscii( ) : ASCII 8 bits
        • toLatin1( ) : Latin-1 (ISO 8859-1) 8 bits
        • toUtf8( ) : UTF-8 Unicode multibyte (1 caractère = 1 à 4 octets)
        • toLocal8Bit( ) : codage local 8 bits

  - qPrintable ( const QString & str )
        • équivalent à : str.toLocal8Bit( ).constData( )
QFile ouverture/fermeture de fichiers
exemples :
   • file = QFile( fileName )

   • if file.open( QFile.ReadOnly | QFile.Text) :

   • if file.open( QFile.WriteOnly ):

   • file.write( “fdsafsdf”)

   • file.flush()

   • file.read()

   • file.close()

  QTextStream lecture, écriture dans fichiers
  exemples :
      • stream = QTextStream( file )

      • txtAll = stream.readAll() ou txtLine = stream.readLine()

      • stream.write
QTextStream

QTextStream
  - lecture ou écriture de texte depuis un QFile :
        • stream = QTextStream( file );

  - méthodes utiles :
        • QString readLine( taillemax = 0 );                 // pas de limite de taille si = 0

        • QString readAll( );     // pratique mais à n’utiliser que pour des petits fichiers
QtGUI
QStyle

• main(args)
      app = QApplication( args)
                                  ./python monAppli –style plastique

Ex: windows, motif, platinum,…
QMainWindow

- Méthode 1: créer une instance de QMainWindow
       win = QMainWindow()
       win.resize(200,300)
- Méthode 2: créer une sous-classe de QMainWindow
       class Win(QMainWindow):
           def __init__(self):
              self.resize(200,300)
QMainWindow :
                          Menus

•   bar = self.menuBar()                   si sous-classe (methode 2)
                                           sinon win.menuBar() (methode 1)
•   fileMenu = bar.addMenu( "File" )

•   newAct = QAction(QIcon("path/images/new.png"), “New…”, self )
•   newAct.setShortcut( “Ctrl+N” )
•   newACT.setToolTip(self.tr(“New File”))
•   newAct.setStatusTip(self.tr(“New file”))

•   fileMenu.addAction(newAct)

•   newAct.triggered.connect( self.new )
QMainWindow
• QMenuBar, QMenu, QAction
• QToolBar
  –   fileToolBar = QToolBar("File")
  –   fileToolBar.addAction(newAct)
  –   mainWindow.addToolBar(fileToolBar)
  –   newAct.setEnabled( false )            grise la commande dans
                                            les menus et la toolbar

• QToolTip, QWhatsThis

• Composant central
       textEdit = TextEdit( self );
       self.setCentralWidget( textEdit );
Buttons

          57
Input Widgets

                58
Containers

   QMidArea           QTabWidget               QGroupBox

                                           QToolBox
        QScrollArea

QWidget; QFrame; QDockWidget; QStackedWidget               59
Views

        QCompleter

              60
standard widgets use data that is part of the widget

View classes operate on external data (the model)

                                                        61
class MyModel(QAbstractTableModel):
    def __init__(self):
         QAbstractTableModel.__init__(self)
         self.myData = 

    def rowCount( self, parent ):          #Type (parent) == QModelIndex
         return 2

    def columnCount( self, parent ):
         return 2

    def data( self, index, role=Qt.DisplayRole):
         if role == Qt.DisplayRole:
               return self.myData(index.row() + 1, index.column()+1)

def main(args):
    app = QApplication(args)
    tableView = QTableView()
    myModel = MyModel()
    tableView.setModel( myModel )
    tableView.show()
    app.exec()                                                             62
Display Widgets

                  63
Boite de dialogue

QProgressDialog

                                     QFileDialog
QMessageBox

                      QColorDialog          QFontDialog
Boîte de dialogue modale

Solution simplifiée
    fileName = QFileDialog.getOpenFileName( self,            //parent
                                            "Open Image”,   // titre
                                            "/home/jana",   // répertoire initial
                                            "*.txt")        // filtre
fileName = QFileDialog.getSaveFileName(…)
Layout

Problèmes
- internationalisation
- redimensionnement
- complexité du code
Layout

                               QFormLayout

              QHBoxLayout

QVBoxLayout                 QGridLayout
Layout : exemple
v_layout = QVBoxLayout( )
v_layout.addWidget( QPushButton( "OK" ) )
v_layout.addWidget( QPushButton( "Cancel" ) )
v_layout.addStretch( )
v_layout.addWidget( QPushButton( "Help" ) )

country_list = QListBox( );
countryList.insertItem( "Canada" );
...etc...

h_layout = QHBoxLayout( )
h_layout.addWidget( country_list )
h_layout.addLayout( v_layout )

top_layout = QVBoxLayout( )
top_layout.addWidget( QLabel( "Select a country" ) )
                                                       Notes sur layouts :
top_layout.addLayout( h_layout );
                                                       - peuvent être emboîtés
container = QWidget()                                  - pas liés à une hiérarchie
container.setLayout( top_layout )                        de conteneurs comme Java
win.setCentralWidget(container)                        - cf. le « stretch »
win.show( )
Arbre d’héritage vs.
arbre d’instanciation
Arbre d’héritage
Principaux widgets :
                      Arbre d’héritage
                                       QCheckBox

QWidget     QAbstractButton           QRadioButton

                                       QToolButton

                                      QPushButton

Hiérarchie de classes (type)
- chaque sous-classe hérite des variables et méthodes de sa superclasse
- du plus général au plus particulier
- héritage simple
Arbre d’instanciation
• Hiérarchie d’instance (=objets)
   – Arbre de filiation des objets
Arbre d’instanciation
• Hiérarchie d’instance (=objets)
   – Arbre de filiation des objets
Arbre d’instanciation
• Les enfants se déclarent auprès de son parent (≠ java)
   – label = Qlabel("Hello", parent);
   – Execptions
        • QFIle, QApplication…
• Si le parent d’un Widget est nul, le Widget est une fenêtre (Window).
• Que font les parents ?
    –   Ils ont une liste des enfants
    –   Ils détruisent automatiquement les enfants quand ils sont détruits
    –   Enable/disable les enfants quand ils enable/disable eux memes
    –   Pareil pour Show/Hide
Arbre d’instanciation
• Hiérarchie d’instance (=objets)
   – Arbre de filiation des objets

• Chaque objet contient ses enfants
   – Clipping : enfants inclus dans parents
   – Superposition : enfants au
     dessus des parents

• Un objet n’a qu’un seul parent
Modules
•   QtCore
•   QtWidgets
•   QtBluetooth
•   QtOpenGL
•   QtSript/QtScriptTools
•   QtSql
•   QtSvg
•   QtWebKit
•   QtXml/QtXmlPatterns
•   QtMultimedia
•   QtSensors
QtNetwork
• QFtp, QHttp, QTcpSocket, QUdpSocket
OpenGL : Box3D
#include 

class Box3D : public QGLWidget {
   Q_OBJECT
   GLuint object;
   GLfloat rotX, rotY, rotZ;

public:
  Box3D( QWidget *parent = 0);
  virtual ~Box3D();

protected:
  virtual void initializeGL();
  virtual void paintGL();
  virtual void resizeGL( int w, int h );
  virtual GLuint makeObject();

public slots:
   void setRotationX(int deg) { rotX = deg; updateGL( ); }
   void setRotationY(int deg) { rotY = deg; updateGL( ); }
   void setRotationZ(int deg) { rotZ = deg; updateGL( ); }
};
modules
•   QtCore
•   QtGui
•   QtNetwork
•   QtOpenGL
•   QtSript/QtScriptTools
•   QtSql
•   QtSvg
•   QtWebKit
•   QtXml/QtXmlPatterns
•   Phonon
•   Qt3Support
Questions
• Quelle est la différence entre l’arbre d’héritage et l’arbre
  d’instanciation?
    • héritage de classe (A hérite de B)
    • héritage d’instances (A contient B)
• Quelle classe utiliser pour créer une fenêtre / Comment ajouter le
  widget central?
    • QMainWindow
    • win.setCentralWidget( myWidget )
• Quels sont les différents layouts?
    • QVBoxLayout; QHBoxLayout; QGridLayout; QFormLayout
• Quelle classe pour un bouton?
    • QPushButton
Outils Qt
Les outils Qt

•   Qt Creator
•   Qt Assistant
•   Qt Examples
•   QtDemo
•   Qt resources
•   Qt Designer
The Qt Resource System
• Mechanism for storing binary files in the application’s
  executable
• Useful if your application needs a certain set of files
  (icons, translation files) and you don’t want to run the risk
  of losing the files

                              resources.qrc
• How to use:
• pyrcc5 - o resources.py resources.qrc
• import resources
                                                              83
Qt Designer

              84
Qt Designer
• sauvegarder le projet en dialog.ui
  (fichier xml)
• transformer en fichier python:
  pyuic5 dialog.ui -o dialog.py
• Insérer la boite de dialogue dans votre code
     import dialog

     class Dialog(QDialog, dialog.UI_Dialog):

         def __init__(self, parent = None):
              super(Dialog, self).__init__(parent)
              self.setupUI(self)
                                                     85
Vous pouvez aussi lire