Participer au site avec un Tip
Rechercher
 

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 :

Enrichissement de la barre de statuts

Mise en oeuvre d'une barre d'outils Mise en oeuvre d'un menu contextuel


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.

Récupération de 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 :

Topographie d'une fenêtre graphique Qt.

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())
Récupération de la barre de statuts de notre fenêtre

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.

Affichage d'une barre de statuts dans votre QMainWindow.
un message temporaire peut être affiché que pendant une durée bien précise. Pour ce faire, il suffit de spécifier un second paramètre (un entier) qui indiquera le temps (en millisecondes) durant lequel le message devra rester visible.
 1 
statusBar.showMessage("Message temporaire", 5_000)
Affichage d'un message temporaire avec une durée limitée

Interactions entre les différentes barres

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())
Exemple d'interaction entre la barre de menu et la barre de statuts

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.

Interactions entre les différentes barres.

Ajouts de widgets permanents 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())
Exemple d'enrichissement de la barre de statuts avec PySide6 et Qt

Et voici le rendu visuel correspondant.

Exemple d'ajout de widgets permanents à la barre de statuts avec PySide6 et Qt

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.
Une classe de thread qui effectue un traitement quelconque.
nous reviendrons plus en détails sur la mise en oeuvre de thread Qt dans un futur chapitre.

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.
Une classe de thread qui effectue un traitement quelconque.

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())


Mise en oeuvre d'une barre d'outils Mise en oeuvre d'un menu contextuel