0% ont trouvé ce document utile (0 vote)
204 vues26 pages

Python Module IHM PyQt

Transféré par

samsoum1
Copyright
© © All Rights Reserved
Nous prenons très au sérieux les droits relatifs au contenu. Si vous pensez qu’il s’agit de votre contenu, signalez une atteinte au droit d’auteur ici.
Formats disponibles
Téléchargez aux formats PDF, TXT ou lisez en ligne sur Scribd
0% ont trouvé ce document utile (0 vote)
204 vues26 pages

Python Module IHM PyQt

Transféré par

samsoum1
Copyright
© © All Rights Reserved
Nous prenons très au sérieux les droits relatifs au contenu. Si vous pensez qu’il s’agit de votre contenu, signalez une atteinte au droit d’auteur ici.
Formats disponibles
Téléchargez aux formats PDF, TXT ou lisez en ligne sur Scribd

26/09/2020

Python pour l’ingénieur

IHM avec PyQt


Module de formation

© Copyright 2020 Cyril Keime & Arnaud Bêche


Introduction
• Qt est une bibliothèque de classes offrant entre autres
des composants d’interface graphique appelés widgets.

• Qt est multi-plateformes (portable) et open-source


(licence GNU LGPL permettant son utilisation légale et
gratuite par des logiciels propriétaires).

• Qt est initialement écrit en langage C++.

• PyQt est un binding de Qt pour le langage Python.


– PyQt n’est pas gratuit pour une utilisation commerciale
– Autre binding Python de Qt : PySide

• Alternatives à Qt :
– Python : Tk (intégré au langage), wxWidgets (wxPython)
– C++ : Gtk, wxWidgets, MFC (Microsoft), etc.

10/10/2021 © Copyright 2020 Cyril Keime & Arnaud Bêche 2


Ressources
• Version de Qt utilisée pour le cours : 5.12 (6 Décembre 2018)

• Site internet de Pyqt :


– [Link]
– Documentation : [Link]

• Site internet de Qt :
– [Link]
– Documentation : [Link]

• La documentation de PyQt n’est pas aussi complète que celle de Qt → il faut


parfois se référer à celle de Qt (en C++, mais la transcription en Python est assez
facile).

10/10/2021 © Copyright 2020 Cyril Keime & Arnaud Bêche 3


Application minimale
import sys
from [Link] import *
from [Link] import *
from [Link] import *

class MaFenetre(QMainWindow):
def __init__(self):
super().__init__()
[Link]('Pyqt')

def main():
app = QApplication([Link])
fenetre = MaFenetre()
[Link]()
[Link]()

if __name__ == '__main__':
main()
10/10/2021 © Copyright 2020 Cyril Keime & Arnaud Bêche 4
Layout de QMainWindow

Menu Bar
Tool Bar

Central Widget

Status Bar

10/10/2021 © Copyright 2020 Cyril Keime & Arnaud Bêche 5


Central Widget
• Central Widget = un objet dérivant de QWidget
– Soit un widget prédéfini
– Soit un widget personnalisé, défini par une classe
dérivant de QWidget

class MaFenetre(QMainWindow):
def __init__(self):
super().__init__()
[Link]('Pyqt')

button = QPushButton('Hello !')

[Link](button)

10/10/2021 © Copyright 2020 Cyril Keime & Arnaud Bêche 6


Widgets prédéfinis

label = QLabel('Mon Titre', self)


[Link]([Link])
image = QLabel(self)
[Link](QPixmap('[Link]'))
bouton = QPushButton('OK', self)

10/10/2021 © Copyright 2020 Cyril Keime & Arnaud Bêche 7


Widget personnalisé
class MonWidget(QWidget):
def __init__(self, parent):
super().__init__(parent)
label = QLabel('Mon Titre', self)
[Link]([Link])
[Link](10, 10, 200, 20)
image = QLabel(self)
[Link](QPixmap('[Link]'))
[Link](10, 30, 200, 100)
bouton = QPushButton('OK', self)
[Link](10, 150, 200, 20)

class MaFenetre(QMainWindow):
def __init__(self):
super().__init__()
[Link]('Pyqt')
central_widget = MonWidget(self)
[Link](central_widget)
[Link](250, 250)

10/10/2021 © Copyright 2020 Cyril Keime & Arnaud Bêche 8


Placement avec Layout
class MonWidget(QWidget):
def __init__(self, parent):
super().__init__(parent)
layout = QVBoxLayout()
label = QLabel('Mon Titre')
[Link]([Link])
image = QLabel()
[Link](QPixmap('[Link]'))
bouton = QPushButton('OK')
[Link](label)
[Link](image)
[Link](bouton)
[Link](layout)

class MaFenetre(QMainWindow):
def __init__(self):
super().__init__()
[Link]('Pyqt')
central_widget = MonWidget(self)
[Link](central_widget)
10/10/2021 © Copyright 2020 Cyril Keime & Arnaud Bêche 9
Imbrication des Layouts
LayoutH
1 2

1
LayoutV
class MonWidget(QWidget): 2
def __init__(self, parent):
super().__init__(parent)
bouton1 = QPushButton('bouton haut gauche')
bouton2 = QPushButton('bouton haut droite')
layoutH = QHBoxLayout()
[Link](bouton1)
[Link](bouton2)
bouton3 = QPushButton('bouton bas')
layoutV = QVBoxLayout()
[Link](layoutH)
[Link](bouton3)
[Link](layoutV)

10/10/2021 © Copyright 2020 Cyril Keime & Arnaud Bêche 10


Types de Layout
• QHBoxLayout
• QVBoxLayout
• QGridLayout
• QFormLayout
(grid)

(form)

10/10/2021 © Copyright 2020 Cyril Keime & Arnaud Bêche 11


Slot et Signal

clic

class MonWidget(QWidget):

def __init__(self):
super().__init__()

[Link] = QPushButton('Cliquez', self)


[Link] = QLineEdit(self)

[Link](self.on_bouton)

signal slot (ou ‘callback’)

def on_bouton(self):
[Link]('clic sur le bouton !')

10/10/2021 © Copyright 2020 Cyril Keime & Arnaud Bêche 12


Slot et Signal
• Un signal peut être accompagné d’une information émise
Ex: valueChanged(int) pour QSpinBox, QDial
Ex: currentTextChanged(str) pour QCombBox
• Dans ce cas, la fonction callback doit avoir des arguments correspondant à ce qu’envoie
le signal, pour réceptionner l’information émise :

émet un str reçoit un str

dial = QDial(self)
spin = QSpinBox(self)
[Link]([Link])
[Link]([Link])
(QSpin)
émet un int reçoit un int (QDial)

10/10/2021 © Copyright 2020 Cyril Keime & Arnaud Bêche 13


Fenêtre plus complexe

class MonWidgetA(QWidget):
def __init__(self, parent):
super().__init__(parent)
layout = QVBoxLayout()
[Link](QPushButton('1'))
[Link](QPushButton('2'))
[Link](QPushButton('3')) A A B
[Link](layout)
class MaFenetre(QMainWindow):
class MonWidgetB(QWidget): def __init__(self):
def __init__(self, parent): super().__init__()
super().__init__(parent) widget1 = MonWidgetA(self)
layout = QVBoxLayout() widget2 = MonWidgetA(self)
[Link](QPushButton('OK')) widget3 = MonWidgetB(self)
[Link](QLineEdit('test')) layout = QHBoxLayout()
[Link](QSlider()) [Link](widget1)
[Link](layout) [Link](widget2)
[Link](widget3)
widget = QWidget()
[Link](layout)
[Link](widget)
10/10/2021 © Copyright 2020 Cyril Keime & Arnaud Bêche 14
Feuilles de style
class MonWidgetA(QWidget):
def __init__(self, parent):
super().__init__(parent)
[Link]('QPushButton { font-weight: bold; font-size: 16px; }')
layout = QVBoxLayout()
[Link](QPushButton('1'))
[Link](QPushButton('2'))
[Link](QPushButton('3'))
[Link](layout)

class MonWidgetB(QWidget):
def __init__(self, parent):
super().__init__(parent)
[Link](' \
QLineEdit { background-color: rgb(0,0,128); color: white; font-family: courier; } \
QPushButton { background-color: rgb(0,128,0); }')
layout = QVBoxLayout()
[Link](QPushButton('OK'))
[Link](QLineEdit('test'))
[Link](QSlider())
[Link](layout)
CSS3

10/10/2021 © Copyright 2020 Cyril Keime & Arnaud Bêche 15


Menu déroulant

class MaFenetre(QMainWindow):
def __init__(self):
super().__init__()

menu1 = [Link]().addMenu('Fichier')

action1 = QAction('Ouvrir', self)


[Link](self.on_ouvrir)
[Link](action1)
méthode de classe à définir
action2 = QAction('Sauvegarder', self)
[Link](self.on_sauver)
[Link](action2)

action3 = QAction('Quitter', self)


[Link](self.on_quitter)
[Link](action3)

menu2 = [Link]().addMenu('Editer')

Voir 10/10/2021 © Copyright 2020 Cyril


aussi : [Link](), [Link](), Keime & Arnaud Bêche
[Link](), sous-menus 16
Quelques autres widgets de Qt
• Boites de dialogues usuelles
– QMessageBox
– QInputDialog
– QFileDialog
• Widgets conteneurs
– QGroupBox
– QTabWidget
– QStackedLayout
• Toolbar et Statusbar
– QToolBar
– QStatusBar
• Widgets complexes
– QListView
– QTreeView
– QTableView

10/10/2021 © Copyright 2020 Cyril Keime & Arnaud Bêche 17


Dessiner
class MaScene(QGraphicsScene):
"""cette classe décrit la scène"""
def __init__(self, parent):
super().__init__(parent)
[Link](0, 0, 300, 300)
texte = [Link]("Hello, world!")
[Link](10, 10)
[Link](50, 50, 200, 200)
stylo = QPen([Link], 5, [Link])
[Link](200, 100, 20, 20, stylo)
brosse = QBrush(QColor(128, 0, 128), [Link])
[Link](100, 200, 50, 50, stylo, brosse)

class MaVueGraphique(QGraphicsView):
"""cette classe fait le rendu (= dessin) de la scène"""
def __init__(self, parent):
super().__init__(parent)
scene = MaScene(self)
[Link](scene)

class MaFenetre(QMainWindow):
def __init__(self):
super().__init__()
[Link]("Dessiner avec PyQt")
vue = MaVueGraphique(self)
[Link](vue)

10/10/2021 © Copyright 2020 Cyril Keime & Arnaud Bêche 18


Clavier et Souris
• Toute classe dérivée de QWidget peut redéfinir des
fonctions héritées pour réagir aux événements
clavier et souris, par exemple :

• keyPressEvent() def keyPressEvent(self, keyevent):


if [Link]() == Qt.Key_Q:
– appelée lorsque qu’une ...

touche du clavier est pressée.

• mousePressEvent() def mousePressEvent(self, mouseevent):


self.x = [Link]().x()
– appelée lorsqu’un bouton self.y = [Link]().y()
de la souris est cliqué.

10/10/2021 © Copyright 2020 Cyril Keime & Arnaud Bêche 19


Timer
def afficher():
• Un timer permet de print("bonjour")
déclencher l’appel d’une
app = QApplication([Link])
fonction à intervalles de timer = QTimer()
temps réguliers. [Link](afficher)
• La classe Qt pour créer # répétition toutes les 1000 millisecondes
[Link](1000)
un timer est QTimer [Link]()

class MonTimer(QTimer):
def __init__(self):
super().__init__()
[Link]([Link])

def ontimer(self):
print("bonjour")

app = QApplication([Link])
timer = MonTimer()
# répétition toutes les 1000 millisecondes [Link]() permet d’arrêter le timer
[Link](1000)
[Link]()

10/10/2021 © Copyright 2020 Cyril Keime & Arnaud Bêche 20


Exercice
• 1re partie
– Créer une classe (scène) affichant une image de carte.
addPixmap(QPixmap("[Link]"))
– La classe contient une fonction permettant de repositionner
cette carte à l’endroit où on clique.
– La classe contient une fonction permettant de créer une 2e carte
quand on appuie sur la touche ‘c’.
– La classe contient une fonction permettant de déplacer la 2e carte
quand on appuie sur les flèches du clavier.
• 2e partie
– La classe contient un timer permettant d’animer la première carte,
en modifiant sa position de quelques pixels à intervalles de temps
réguliers.
– La classe contient une fonction permettant de mettre l’animation en
pause quand on appuie sur la touche ‘p’.
10/10/2021 © Copyright 2020 Cyril Keime & Arnaud Bêche 21
Exercice : mini Pacman (3e partie)
• Partir des modules [Link], [Link] et [Link] fournis sur [Link]

• Module [Link]:
– coder le constructeur de la classe PacmanParams de manière à obtenir l'interface ci-dessous
• Utiliser QSpinBox pour saisir les dimensions du plateau de jeu et le nombre de fantômes
• Utiliser QFormLayout pour titrer et disposer les 3 options
• connecter les méthodes on_start et on_stop aux boutons start et stop. Ces méthodes ne font rien pour le moment.

10/10/2021 © Copyright 2020 Cyril Keime & Arnaud Bêche 22


Exercice : mini Pacman (3e partie)
• Module [Link]
– Coder le constructeur et la méthode start() de PacmanControler
• Attributs de la classe PacmanControler :
– [Link] : liste d'objets fantômes (Entity)
– [Link] : objet pacman (Pacman)
– [Link] : timer
– [Link] : largeur du plateau
– [Link] : hauteur du plateau
• Dans le constructeur :
– Créer l'attribut timer (classe QTimer) et le connecter à la méthode next()
• Dans start():
– Créer nb_ghosts objets fantômes et leur donner une position initiale aléatoire
– Créer un objet pacman et lui donner une position initiale aléatoire
– Démarrer le timer
• Dans stop()
– Arrêter le timer
• Appeler les méthodes start() et stop() du contrôleur au moment adéquat dans la classe PacmanParams
([Link]). Bien prendre en compte les paramètres saisis dans l'interface (largeur, hauteur, nombre de
fantômes). Vérifier que ces paramètres parviennent avec la bonne valeur à la méthode start().
• Vérifier que la méthode next() est bien appelée à intervalle de temps régulier lorsqu'on clique sur le bouton
Start (mettre un print dans la méthode next()). Vérifier que cliquer sur le bouton Stop arrête bien le timer.

10/10/2021 © Copyright 2020 Cyril Keime & Arnaud Bêche 23


Exercice : mini Pacman (3e partie)
• Module [Link]:
– Classe PacmanScene :
• Constructeur :
– Initialiser la scène à une dimension de 512 x 512 pixels
• Méthode refresh() :
– Dessiner le plateau de jeu en allouant 25x25 pixels à chaque case du plateau de jeu
» Dessiner le fond en gris et les contours du plateau en noir (rectangles)
» Dessiner chaque fantôme (disque de couleur rouge)
» Dessiner Pacman (disque de couleur jaune)

• Module [Link]
– Compléter la méthode next() :
• Déplacer les fantômes
• Déplacer Pacman
• Si un fantôme est "mangé", le supprimer
de la liste des fantômes
• S'il n'y a plus de fantôme, arrêter le timer
• Provoquer un rafraichissement de tous
les "clients" du contrôleur

• Tester
• Vérifier le bon déplacement des
entités
• Vérifier la disparition des fantômes mangés
• Vérifier que la fin de partie se passe bien
(Pacman s'arrête)
• Vérifier qu'on peut démarrer une nouvelle partie,
en modifiant ou pas les paramètres du jeu

10/10/2021 © Copyright 2020 Cyril Keime & Arnaud Bêche 24


Exercice : mini Pacman (3e partie)
• Module [Link]:

– Téléportation de Pacman à la souris :


• Ajouter une méthode move_pacman(x, y) au contrôleur qui téléporte instantanément
Pacman à la position (x, y). Ne pas permettre de téléporter Pacman en dehors du plateau
de jeu ou sur la bordure.
• Coder la méthode mousePressEvent pour que Pacman soit téléporté sur le curseur de
souris lorsqu'on clique sur le plateau de jeu.

– Mettre le jeu en pause au clavier (touche P)


• Implémenter la méthode keyPressEvent() (module [Link]) pour transmettre la touche du
clavier saisie à la méthode process_keypress() du contrôleur
• Implémenter la méthode process_keypress() (module [Link]) pour activer / désactiver
la pause par la touche P. La mise en pause consiste à stopper le timer. Redémarrer le timer
pour enlever la pause, sans réinitialiser le jeu.
• Vérifier le bon comportement si le jeu est relancé (bouton start) pendant la pause.

10/10/2021 © Copyright 2020 Cyril Keime & Arnaud Bêche 25


Exercice : mini Pacman (3e partie)
• Quelques améliorations :
– Adapter automatiquement la dimension en pixels d'une case de plateau (actuellement fixé à
25x25 pixels) pour que la plateau occupent toujours 512 pixels quel que soit la largeur et la
hauteur choisies
– Lorsqu'il n'y a plus de fantômes, afficher "Game Over" par-dessus le plateau de jeu (jusqu'au
démarrage d'une nouvelle partie avec start)
– Afficher le nombre de fantômes encore en vie dans la barre des paramètres
– Ajouter un paramètre permettant de modifier la vitesse du jeu pendant une partie (ajouter un
widget QSpinBox dans les paramètres, utiliser la méthode setInterval du timer).

10/10/2021 © Copyright 2020 Cyril Keime & Arnaud Bêche 26

Vous aimerez peut-être aussi