Accès rapide :
Récupération de la barre de statuts
Interactions entre les différentes barres
Ajouts de widgets permanents dans la barre de statuts.
Pour rappel, une application graphique classique propose un certain nombre de barres standards : la barre de menu, une ou plusieurs barres d'outils et la barre de statuts.
Petit point de terminologie : certains parlent de « la barre de statuts » et d'autres préfèrent la terminologie de barre d'états. A vous de choisir.
Ces barres se positionnent traditionnellement ainsi :
Pour récupérer la barre de statuts de votre QMainWindow
, vous devez invoquer
la méthode QMainWindow.statusBar
Une fois que la barre d'états est présente dans la fenêtre, vous pouvez y insérer un message temporaire en invoquant la méthode
QStatusBar.showMessage
.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
import sys from PySide6.QtWidgets import QApplication, QMainWindow, QStatusBar class MyWindow(QMainWindow): def __init__(self): super().__init__() self.setWindowTitle("Exemple de récupération de la barre de statuts avec Python and PySide6/Qt") self.resize(1100, 400) # On récupère la barre de statuts (de type QStatusBar) de la fenêtre principale. statusBar: QStatusBar = self.statusBar() # On définit le texte initialement affiché dans la barre de statuts. statusBar.showMessage(self.windowTitle()) if __name__ == "__main__": app = QApplication(sys.argv) myWindow = MyWindow() myWindow.show() sys.exit(app.exec()) |
Et voici le résultat produit par cet exemple. Notez la présence d'un « gripper » en bas à droite : cet élément intrinsèque à la barre de statuts, permet de mieux signaler la possibilité de retailler la fenêtre.
1 |
statusBar.showMessage("Message temporaire", 5_000)
|
Comme nous l'avons déjà vu dans les chapitres précédents, les barres de menu, d'outils et de statuts sont interconnectées. Ainsi, si vous passer la souris
sur un des éléments de la barre de menu (ou d'une barre d'outils) le statusTip
de l'action associée sera affiché dans la zone informative
(à gauche) de la barre de statuts. Voici un exemple simple.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 |
import sys from PySide6.QtCore import Slot from PySide6.QtGui import QIcon, QAction from PySide6.QtWidgets import QApplication, QMainWindow class MyWindow(QMainWindow): def __init__(self): super().__init__() self.setWindowTitle("Interactions entre les différentes barres.") self.setWindowIcon(QIcon("icons/file.png")) self.resize(600, 150) self.createActions() self.createMenuBar() statusBar = self.statusBar() statusBar.showMessage(self.windowTitle()) # Définition du message initial def createActions(self): self.actNew = QAction(QIcon("icons/new.png"), "&New", self) self.actNew.setShortcut("Ctrl+N") self.actNew.setStatusTip("New document") self.actNew.triggered.connect(self.newDocument) self.actOpen = QAction(QIcon("icons/open.png"), "&Open...", self) self.actOpen.setShortcut("Ctrl+O") self.actOpen.setStatusTip("Open file") self.actSave = QAction(QIcon("icons/save.png"), "&Save", self) self.actSave.setShortcut("Ctrl+S") self.actSave.setStatusTip("Save File") self.actExit = QAction(QIcon("icons/exit.png"), "Exit", self) self.actExit.setShortcut("Alt+F4") self.actExit.setStatusTip("Exit") # La méthode close est directement fournie par la classe QMainWindow. self.actExit.triggered.connect(self.close) def createMenuBar(self): menuBar = self.menuBar() file = menuBar.addMenu("&File") file.addAction(self.actNew) file.addSeparator() file.addAction(self.actOpen) file.addAction(self.actSave) file.addSeparator() file.addAction(self.actExit) @Slot() def newDocument(self): print("New document is requested") if __name__ == "__main__": app = QApplication(sys.argv) myWindow = MyWindow() myWindow.show() sys.exit(app.exec()) |
Placez maintenant la souris sur un des éléments de la barre de menu pour voir apparaître le message statusTip
dans la barre de statuts.
Dans PySide6, un widget permanent signifie que le widget est toujours visible dans la barre d'état, indépendamment de la présence de messages temporaires. Les messages temporaires sont affichés à gauche de la barre d'état et sont remplacés au fur et à mesure de l'évolution de l'application. Les widgets permanents, en revanche, sont alignés à droite et ne disparaissent pas à moins d'être explicitement supprimés.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
import sys from PySide6.QtWidgets import QApplication, QMainWindow, QStatusBar, QProgressBar, QLabel class MyWindow(QMainWindow): def __init__(self): super().__init__() self.setWindowTitle("MenuBar with Python") self.resize(1100, 400) # On créé la barre de statuts (de type QStatusBar) avec son message initial bar: QStatusBar = self.statusBar() bar.showMessage("Exemple de définition d'une barre de statuts avec Python and Qt") # Une barre de progression progress = QProgressBar() progress.setMaximumHeight(20) progress.setValue(50) # Un label avec un message quelconque label = QLabel("Text position: 31,25") # On ajoute nos deux widgets permanents à la droite de la barre de status. bar.addPermanentWidget(progress) bar.addPermanentWidget(label) if __name__ == "__main__": app = QApplication(sys.argv) myWindow = MyWindow() myWindow.show() sys.exit(app.exec()) |
Et voici le rendu visuel correspondant.
Histoire de finir sur un exemple un peu plus sympathique, voici comment lancer un pseudo-traitement de longue durée (imaginez des vrais calculs qui prennent un peu de temps) tout en indiquant l'avancement du traitement dans le widget QProgressBar de la barre d'états.
Pour réaliser cette opération, on utilise une technique de multithreading. Le principe est simple : au lieu de lancer un traitement long et bloquant sur le thread principal de l'application (ce qui aurait pour effet de geler l'interface utilisateur), on lance ce traitement dans un thread à part. Ainsi, le thread principal peut continuer à gérer l'interface utilisateur sans être interrompu.
Dans notre cas, le « pseudo-traitement de longue durée » est simulé par une boucle qui compte de 0 à 100 avec une petite pause à chaque itération,
simulant une opération qui prend du temps. Cette boucle est exécutée dans la méthode run()
de la classe MyThread
, qui est une
sous-classe de QThread
: c'est ce qu'on appelle le thread de traitement.
1 2 3 4 5 6 7 8 |
class MyThread(QThread): def __init__(self): QThread.__init__(self) def run(self): for i in range(101): # on compte de 0 à 100 inclus, donc 101 valeurs. time.sleep(0.05) # On fait une petite pause. |
Mais, comment signaler à l'interface utilisateur l'avancement de ce traitement ? C'est là que les signaux entrent en jeu.
Qt propose un mécanisme de signaux et de slots pour communiquer entre différents objets, threads inclus.
Dans notre cas, nous avons créé un signal progress
dans la classe MyThread.
Ce signal est émis à chaque itération de la boucle, avec la valeur courante de l'itérateur comme argument.
1 2 3 4 5 6 7 8 9 10 11 12 |
class MyThread(QThread): # Créer un signal qt associée à une valeur entière. progress = Signal(int) def __init__(self): QThread.__init__(self) def run(self): for i in range(101): # on compte de 0 à 100 inclus, donc 101 valeurs. time.sleep(0.05) # On fait une petite pause. self.progress.emit(i) # Émettre le signal avec la valeur de la variable i. |
Il ne reste plus qu'à intercepter le signal dans l'interface graphique pour propager la progression dans la barre de statuts. Et voici le code complet.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 |
import sys import time from PySide6.QtCore import QThread, Signal from PySide6.QtWidgets import QApplication, QMainWindow, QStatusBar, QProgressBar, QLabel, \ QVBoxLayout, QPushButton, QWidget, QSizePolicy # Cette classe de thread simule un traitement long et émet # périodiquement un signal pour informer de sa progression. class MyThread(QThread): # Créer un signal qt associée à une valeur entière. progress = Signal(int) def __init__(self): QThread.__init__(self) def run(self): for i in range(101): # on compte de 0 à 100 inclus, donc 101 valeurs. time.sleep(0.05) # On fait une petite pause. self.progress.emit(i) # Émettre le signal avec la valeur de la variable i. class MyWindow(QMainWindow): def __init__(self): super().__init__() self.setWindowTitle("MenuBar with Python") self.resize(1100, 400) # On définit un QVBoxLayout contenant un bouton. vboxLayout = QVBoxLayout() startButton = QPushButton("Start progression") startButton.clicked.connect(self.startLongProcessing) vboxLayout.addWidget(startButton) # On injecte un widget central avec le layout précédent. centralWidget = QWidget() centralWidget.setLayout(vboxLayout) self.setCentralWidget(centralWidget) # On crée la barre de status avec son message initial. bar: QStatusBar = self.statusBar() bar.showMessage("Exemple de définition d'une barre de statuts avec Python and Qt") # Une barre de progression progress = QProgressBar() progress.setMaximumHeight(20) progress.setValue(0) # Un label avec un message quelconque label = QLabel("Text position: 31,25") # On ajoute nos deux widgets permanents à la droite de la barre de status. bar.addPermanentWidget(progress) bar.addPermanentWidget(label) # On définit un thread qui exécute une longue tâche en parallèle. Dans ce cas subtil, # le slot est directement fourni pas le widget de type QProgressBar (la méthode # setValue, qui y est déjà définie en tant que slot). self.longProcessing = MyThread() self.longProcessing.progress.connect(progress.setValue) # Le gestionnaire de click de notre bouton : il lance le thread en y invoquant la méthode start. def startLongProcessing(self): self.longProcessing.start() if __name__ == "__main__": app = QApplication(sys.argv) myWindow = MyWindow() myWindow.show() sys.exit(app.exec()) |
Améliorations / Corrections
Vous avez des améliorations (ou des corrections) à proposer pour ce document : je vous remerçie par avance de m'en faire part, cela m'aide à améliorer le site.
Emplacement :
Description des améliorations :