Cours de Python - PyQt 5

version 1.01, dernière mise à jour le 8 avril 2016.

   

Table des matières (TdM)

  1. I. Introduction
  1. II. Pour débuter...
    1. Une fenêtre vide...
  1. III. Créer une application
    1. Le squelette
    2. Widgets
  1. IV. Mise en page
    1. Box layout
    2. Grille
    3. Application d'une mise en page à une fenêtre d'application
  1. V. Gestion des événements
    1. Introduction
    2. Mise en œuvre
      1. Sans gestionnaire
      2. Avec un gestionnaire

Retour au menu

Contenu du cours

I. Introduction

Python est un langage qui peut être utilisé pour réaliser des programmes évolués. Pour cela, il faut pouvoir réaliser des interfaces utilisateur. Il existe plusieurs bibliothèques pour cela ; certaines ont été portées sur Python.

Nous allons aborder dans ce cours PyQt, pour laquelle il est plus facile de trouver un mode d'installation simple sous Windows. À la date d'écriture de ce cours, la bibliothèque est en version 5.5.1, compatible avec Python 3.4. Au-delà d'une bibliothèque pour la création d'une interface graphique, PyQt embarque aussi de nombreux composants, sous la forme de modules spécialisés. Nous n'utiliserons dans ce cours d'initiation que les modules QtCore et QtGui, parmi la vingtaine disponible.

II. Pour débuter...

1. Une fenêtre vide...

PyQt5 permet de se simplifier la vie, et de coder simplement une interface utilisateur. Analysons l'exemple suivant...

import sys
from PyQt5.QtWidgets import QApplication, QWidget

monApp=QApplication(sys.argv)
w=QWidget()
w.resize(500,300)
w.move(500, 500)
w.setWindowTitle("Titre de fenêtre")
w.show()

sys.exit(monApp.exec_())

Dans cet exemple, on commence par importer les classes QApplication et QWidget du module PyQt5.QtWidgets. On définit ensuite une nouvelle application (monApp), puis un « widget », auquel on donne une largeur de 500 pixels, une hauteur de 300 pixels, et que l'on place à 500 pixels du bord gauche de l'écran, et 500 pixels à partir du haut. On lui affecte ensuite un titre, puis on le montre. L'instruction sys.exit(monApp.exec_()) permet de quitter l'application en cliquant sur la croix telle qu'elle est définie par le système d'exploitation sur la fenêtre.

Si l'on veut concevoir de manière un peu plus orientée objet (ce qui permet de réutiliser un widget), on écrira plutôt...

import sys
from PyQt5.QtWidgets import QApplication, QWidget
							
class Fen(QWidget):
	def __init__(self):
		super().__init__()
		self.lanceUI()
							
	def lanceUI(self):
		self.resize(500,300)
		self.move(500, 500)
		self.setWindowTitle("Titre de fenêtre")
		self.show()
							
monApp=QApplication(sys.argv)
w=Fen()
sys.exit(monApp.exec_())
Widget de base
Code source

La méthode super() permet de remonter à la classe dont on hérite.

>Retour à la TdM

III. Créer une application

1. Le squelette

Créer un widget n'est pas créer une application, mais un composant d'une application. Les widgets sont positionnés à l'intérieur d'une fenêtre principale. En voici un exemple

import sys
from PyQt5.QtWidgets import QMainWindow, QApplication, QAction, qApp

class Principale(QMainWindow):
	def __init__(self):
		super().__init__()
		self.setUI()

	def setUI(self):
		exitAction=QAction('&Exit', self)
		exitAction.setShortcut('Ctrl+Q')
		exitAction.setStatusTip("Quitter l'application")
		exitAction.triggered.connect(qApp.exit)

		menu=self.menuBar()
		fichierMenu=menu.addMenu("&Fichier")
		fichierMenu.addAction(exitAction)
		
		self.barreOutils=self.addToolBar('Quitter')
		self.barreOutils.addAction(exitAction)

		self.setGeometry(300,300,500,250)
		self.setWindowTitle('Fenêtre principale')
		self.statusBar().showMessage('Barre de statut')
		self.show()

monApp=QApplication(sys.argv)
fenetre=Principale()
sys.exit(monApp.exec_())
Application de base Qt5
Code source

La classe QAction permet de définir des actions, que l'on peut attacher soit à une barre de menu (activée grâce à la méthode menuBar), soit à une barre d'outils (méthode addToolBar).

La méthode setGeometry permet de spécifier la position et la taille de la fenêtre, en précisant dans cet ordre la position par rapport au coin supérieur gauche, largeur et hauteur.

>Retour à la TdM

2. Widgets

Les widgets sont les composants de base de l'application. En voici quelques-uns...

import sys
from PyQt5.QtWidgets import QMainWindow, QApplication, QAction, qApp, QTextEdit, QPushButton, QHBoxLayout, QWidget, QVBoxLayout,QToolTip, QLineEdit, QLabel, QCheckBox, QComboBox
	
class Principale(QMainWindow):
	def __init__(self):
		super().__init__()
		self.setUI()
	
	def setUI(self):
		zoneTexte=QTextEdit()
		btnOK=QPushButton("OK", self)
		zoneLigne=QLineEdit()
		label=QLabel("Champ texte")
		case=QCheckBox("Case", self)
		combo=QComboBox(self)
		
		btnOK.resize(btnOK.sizeHint())
		btnOK.setToolTip("Ceci est un bouton <i>OK</i>")
		
		combo.addItem("Choix 1")
		combo.addItem("Choix 2")
		combo.addItem("Choix 3")
		combo.addItem("Choix 4")
		
		hbox=QHBoxLayout()
		hbox.addStretch(1)
		hbox.addWidget(label)
		hbox.addWidget(zoneLigne)
		hbox.addWidget(zoneTexte)
		hbox.addWidget(btnOK)
		hbox.addWidget(case)
		hbox.addWidget(combo)
		vbox=QVBoxLayout()
		
		w=QWidget()
		w.setLayout(hbox)
		
		self.setCentralWidget(w)
		
		#Définition des actions
		exitAction=QAction('&Exit', self)
		exitAction.setShortcut('Ctrl-Q')
		exitAction.setStatusTip("Quitter l'application")
		exitAction.triggered.connect(qApp.exit)
		
		menu=self.menuBar()
		fichierMenu=menu.addMenu("&Fichier")
		fichierMenu.addAction(exitAction)
		
		self.barreOutils=self.addToolBar('Quitter')
		self.barreOutils.addAction(exitAction)
		
		self.setGeometry(300,300,500,250)
		self.setWindowTitle('Fenêtre principale')
		self.statusBar().showMessage('Barre de statut')
		self.show()
	
monApp=QApplication(sys.argv)
fenetre=Principale()
sys.exit(monApp.exec_())
Quelques widgets
Code source

La plupart des noms sont explicites ; néanmoins voici quelques détails sur certaines méthodes :

Nous allons revenir sur la mise en page, limitée ici.

>Retour à la TdM

IV. Mise en page

1. Box layout

Les classes QHBoxLayout et QVBoxLayout permettent d'aligner des contenus horizontalement ou verticalement. Combinés, cela permet une grande souplesse. Supposons que l'on veuille par exemple ajouter trois boutons en bas de la fenêtre, répartis régulièrement :

import sys
from PyQt5.QtWidgets import QWidget, QApplication, QPushButton, QHBoxLayout, QVBoxLayout
	
class Principale(QWidget):
	def __init__(self):
		super().__init__()
		self.setUI()
	
	def setUI(self):
	
		btn1=QPushButton("Bouton1")
		btn2=QPushButton("Bouton2")
		btn3=QPushButton("Bouton3")
		
		hbox=QHBoxLayout()
		hbox.addStretch(1)
		hbox.addWidget(btn1)
		hbox.addStretch(1)
		hbox.addWidget(btn2)
		hbox.addStretch(1)
		hbox.addWidget(btn3)
		hbox.addStretch(1)
		
		vbox=QVBoxLayout()
		vbox.addStretch(1)
		vbox.addLayout(hbox)
		
		self.setLayout(vbox)
		
		self.setGeometry(300,300,500,250)
		self.setWindowTitle('Fenêtre principale')
		
		self.show()
	
monApp=QApplication(sys.argv)
fenetre=Principale()
sys.exit(monApp.exec_())
Mise en page avec boîtes horizontales et verticales
Code source

On commence par créer les trois boutons. On crée ensuite un layout horizontal avec QHBoxLayout. La méthode addStretch permet d'ajouter un espace de largeur variable, et qui s'ajuste en fonction de la largeur de la fenêtre. Ici, on insère donc un espace variable, un bouton, un espace variable, un deuxième bouton, un espace variable, le dernier bouton et un dernier espace variable.

On crée ensuite un layout vertical, auquel on ajoute un espace variable puis le layout horizontal que l'on vient de créer. Comme on n'ajoute rien en-dessous, le layout hbox sera toujours calé sur le bas de la fenêtre.

Une telle mise en page permet de s'assurer que les boutons restent en permanence régulièrement répartis et calés en bas de la fenêtre.

>Retour à la TdM

2. Grille

Un autre système de mise en page commode est la grille, avec la classe QGridLayout.

import sys
from PyQt5.QtWidgets import QWidget, QApplication, QPushButton, QGridLayout
	
class Principale(QWidget):
	def __init__(self):
		super().__init__()
		self.setUI()
	
	def setUI(self):
	
		btn1=QPushButton("Bouton1")
		btn2=QPushButton("Bouton2")
		btn3=QPushButton("Bouton3")
		btn4=QPushButton("Bouton4")
		btn5=QPushButton("Bouton5")
		btn6=QPushButton("Bouton6")
		
		grille=QGridLayout()
		self.setLayout(grille)
		grille.addWidget(btn1, 1,1)
		grille.addWidget(btn2, 1,2)
		grille.addWidget(btn3, 1,3)
		grille.addWidget(btn4, 2,1)
		grille.addWidget(btn5, 2,2)
		grille.addWidget(btn6, 2,3)
		
		self.setGeometry(300,300,500,250)
		self.setWindowTitle('Fenêtre principale')
		
		self.show()
	
monApp=QApplication(sys.argv)
fenetre=Principale()
sys.exit(monApp.exec_())
Mise en page avec grille
Code source

>Retour à la TdM

3. Application d'une mise en page à une fenêtre d'application

Les layouts ne peuvent être appliqués qu'à des widgets, pas à une classe héritée de QMainWindow comme nous l'avons vu précédemment. Pour cela, il faut déclarer qu'un widget est le widget central de la fenêtre. Si on a défini un layout miseEnPage (cela pourrait être par exemple l'objet grille de l'exemple précédent), on écrira

centre=QWidget()
centre.setLayout(miseEnPage)
	
self.setCentralWidget(centre)

>Retour à la TdM

V. Gestion des événements

1. Introduction

Il existe une multitude d'événements susceptibles de changer l'état d'une application ou des données qu'elle traite. Ces événements peuvent résulter d'une action de l'utilisateur (comme un clic), ou bien de l'activation d'une connexion Internet, du signal envoyé par une horloge, etc. Dans tous les cas, trois éléments sont concernés :

>Retour à la TdM

2. Mise en œuvre

a. Sans gestionnaire

PyQt5 utilise les concepts de signal et de slot pour gérer les événements. Voici un exemple simple :

import sys
from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import QWidget, QApplication, QVBoxLayout, QLCDNumber, QSlider
	
class Principale(QWidget):
	def __init__(self):
		super().__init__()
		self.setUI()
	
	def setUI(self):
		lcd=QLCDNumber(self)
		slider=QSlider(Qt.Horizontal, self)
		
		miseEnPage=QVBoxLayout()
		miseEnPage.addWidget(slider)
		miseEnPage.addWidget(lcd)
		self.setLayout(miseEnPage)
		
		slider.valueChanged.connect(lcd.display)
		
		self.setGeometry(300,300,200,100)
		self.setWindowTitle('Fenêtre principale')
		
		self.show()
	
monApp=QApplication(sys.argv)
fenetre=Principale()
sys.exit(monApp.exec_())
Un slider et un affichage 7 segments
Code source

QLCDNumber et QSlider sont des classes permettant d'afficher un nombre au format LCD et une barre de réglage. L'événement valueChanged du slider est connecté à l'affichage du LCD.

b. Avec un gestionnaire

On peut également, tout comme en JavaScript, associer un gestionnaire d'événement :

import sys
from PyQt5.QtWidgets import QWidget, QApplication, QPushButton, QGridLayout, QMessageBox
	
class Principale(QWidget):
	def __init__(self):
		super().__init__()
		self.setUI()
	
	def afficheMessage(self):
		message=QMessageBox()
		message.setText("<b>Bouton cliqué</b>")
		message.setInformativeText("avec deux boutons...")
		message.setWindowTitle("Message d'alerte")
		message.setStandardButtons(QMessageBox.Ok | QMessageBox.Cancel)
		message.exec()
	
	def setUI(self):
	
		btn=QPushButton("Bouton", self)
		
		btn.clicked.connect(self.afficheMessage)
		
		self.setGeometry(300,300,100,30)
		self.setWindowTitle('Fenêtre principale')
		
		self.show()
	
monApp=QApplication(sys.argv)
fenetre=Principale()
sys.exit(monApp.exec_())
Un bouton
Code source
Une boîte d'information, avec pour titre Message d'alerte, un texte Bouton cliqué et un sous-titre 'avec deux boutons' et deux boutons OK et Cancel

On associe cette fois-ci au clic sur le bouton le gestionnaire afficheMessage, qui affiche des informations diverses dans une boîte...

>Retour à la TdM

Historique de ce document

Conditions d'utilisation et licence

Creative Commons License
Cette création est mise à disposition par Gilles Chagnon sous un contrat Creative Commons.

Retour au menu