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 :

Mise en oeuvre d'une barre de menu

Définition d'actions Qt Définition d'un menu réutilisable


Accès rapide :
La vidéo
Obtenir la barre de menu de votre fenêtre principale
Ajouter un menu déroulant dans la barre de menu
Ajouter un menu déroulant dans un menu déroulant
Travaux pratiques
L'énoncé
La correction

La vidéo

Cette vidéo vous montre comment constituer une barre de menu en Qt et utilisant les actions étudiées précédemment.


Mise en oeuvre d'une barre de menu.

Obtenir la barre de menu de votre fenêtre principale

Pour rappel, une fenêtre principale (classe QMainWindow) est divisée en plusieurs zones : l'emplacement pour la barre de menu, les emplacements relatifs à vos barres d'outils, la zone centrale et la zone dédiée à la barre de statuts. Voici un diagramme qui illustre cette division de l'espace de la fenêtre principale.

Topographie d'une fenêtre Qt.

Comme nous l'avons vu dans le précédent chapitre, la barre de menu est déjà gérée par votre fenêtre. Pour l'obtenir, il vous suffit d'invoquer la méthode menuBar. En fait, c'est cette méthode qui réalise l'instanciation de la barre de menu : si vous ne l'invoquer pas, vous ne visualiserez pas votre barre. Voici un exemple d'acquisition de la barre de menu.

 1 
 2 
 3 
 4 
 5 
 6 
 7 
 8 
 9 
 10 
 11 
 12 
 13 
 14 
 15 
 16 
 17 
 18 
 19 
 20 
 21 
 22 
 23 
 24 
import sys

from PySide6.QtGui import QIcon
from PySide6.QtWidgets import QApplication, QMainWindow


class MyWindow(QMainWindow):

    def __init__(self):
        super().__init__()
        self.setWindowTitle("Exemple de définition d'une barre de menu Qt")
        self.setWindowIcon(QIcon("icons/file.png"))
        self.resize(600, 150)

        # On récupère la barre de menu de la fenêtre principale.
        menuBar = self.menuBar()
        # Vous pouvez maintenant insérer vos actions dans la barre de menu.


if __name__ == "__main__":
    app = QApplication(sys.argv)
    myWindow = MyWindow()
    myWindow.show()
    sys.exit(app.exec())
Obtenir la barre de menu de votre fenêtre principale.

Ajouter un menu déroulant dans la barre de menu

Pour ajouter un menu dans la barre de menu, vous devez utiliser la méthode addMenu. Celle-ci accepte une chaîne de caractères : le libellé affiché en haut du menu déroulant.

Tout comme pour les actions, étudiées dans le chapitre précédent, vous pouvez ajouter un caractère souligné pour permettre l'accéder au menu à partir du clavier. Ainsi, dans l'exemple suivant, la lettre F servira à l'ouverture du menu File (il faudra appuyer simultanément sur les touches ALT et F).

 1 
 2 
menuBar = self.menuBar()
file = menuBar.addMenu("&File")
Ajout d'un menu déroulant dans la barre de menu.

Une fois le menu en place, vous pouvez y ajouter vos actions. Il est possible de regrouper plusieurs actions dans un même compartiment en rajoutant des séparateurs dans le menu déroulant. Dans l'exemple suivant, j'ai essayé de structurer mon code en plusieurs méthodes afin d'éviter d'avoir un trop gros constructeur.

 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("Exemple de définition d'une barre de menu Qt")
        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())
Ajout d'un menu déroulant dans la barre de menu.
vos actions pourront aussi être injectées dans une barre d'outils ou dans des menus contextuels. Le fait de les déclarer sous forme d'attributs nous permet de les retrouver dans la méthode de construction de la barre de menu. Mais vous pourrez aussi y accéder dans d'autres méthodes (createToolBars...).

Et voici le résultat obtenu si vous déroulez le menu File.

Ajout d'un menu déroulant dans la barre de menu.
je vous laisse, bien entendu, libre de choisir les icônes que vous souhaitez pour vos actions. Néanmoins, si vous n'avez pas encore d'icônes et que vous souhaitez rapidement faire quelques premiers tests, vous pouvez télécharger le jeu d'icônes que j'utilise pour mes exemples.
certains d'entre vous doivent se demander pourquoi le texte de l'action d'ouverture de fichier se termine par .... C'est une convention assez classique : si votre action ouvre une nouvelle boîte de dialogue, alors on rajoute ces trois caractères. Amusez-vous à ouvrir le menu File de PyCharm et vous verrez qu'eux aussi respectent cette convention.

Ajouter un menu déroulant dans un menu déroulant

Un menu déroulant peut proposer un (ou plusieurs) sous-menu(s). Pour ce faire, il faut invoquer la méthode addMenu sur le menu parent. Il n'y a pas de limite de profondeur, si ce n'est que votre interface doit rester ergonomique. Voici comment ajouter un sous-menu à votre menu File.

 1 
 2 
 3 
 4 
 5 
 6 
 7 
 8 
 9 
 10 
 11 
 12 
 13 
 14 
 15 
 16 
 17 
 18 
 19 
 20 
 21 
 22 
def createMenuBar(self):
    menuBar = self.menuBar()

    actFile1 = QAction(QIcon("icons/new.png"), "File-1.txt", self)
    actFile1.setStatusTip(actFile1.text())
    actFile2 = QAction(QIcon("icons/new.png"), "File-2.txt", self)
    actFile2.setStatusTip(actFile2.text())
    actFile3 = QAction(QIcon("icons/new.png"), "File-3.txt", self)
    actFile3.setStatusTip(actFile3.text())

    file = menuBar.addMenu("&File")
    file.addAction(self.actNew)
    file.addSeparator()
    file.addAction(self.actOpen)
    file.addAction(self.actSave)
    file.addSeparator()
    recentFiles = file.addMenu("Recent files")
    recentFiles.addAction(actFile1)
    recentFiles.addAction(actFile2)
    recentFiles.addAction(actFile3)
    file.addSeparator()
    file.addAction(self.actExit)
Ajouter un menu déroulant dans un menu déroulant.

Et voici le rendu visuel produit par cet exemple.

Ajout d'un menu déroulant dans la barre de menu.

Travaux pratiques

L'énoncé

En repartant de l'exemple proposé ci-dessus, veuillez rajouter un menu « Edit » (avec les éléments « Undo », « Redo », « Copy », « Cut » et « Paste ») ainsi qu'un autre menu « Help » (avec un élément « About... »).

Essayez de faire l'exercice sans regarder directement la correction ci-dessous. ;-)

La correction

 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 
 77 
 78 
 79 
 80 
 81 
 82 
 83 
 84 
 85 
 86 
 87 
 88 
 89 
 90 
 91 
 92 
 93 
 94 
 95 
 96 
 97 
 98 
 99 
 100 
 101 
 102 
 103 
 104 
 105 
 106 
 107 
 108 
 109 
 110 
 111 
 112 
 113 
 114 
 115 
 116 
 117 
 118 
 119 
import sys

from PySide6.QtCore import Slot
from PySide6.QtGui import QIcon, QAction
from PySide6.QtWidgets import QApplication, QMainWindow, QFileDialog, QMessageBox


class MyWindow(QMainWindow):

    def __init__(self):
        super().__init__()
        self.setWindowTitle("Exemple de définition d'une barre de menu Qt")
        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.actOpen.triggered.connect(self.openDocument)

        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)

        self.actUndo = QAction(QIcon("icons/undo.png"), "&Undo", self)
        self.actUndo.setShortcut("Ctrl+Z")
        self.actUndo.setStatusTip("Undo")

        self.actRedo = QAction(QIcon("icons/redo.png"), "&Redo", self)
        self.actRedo.setShortcut("Ctrl+Y")
        self.actRedo.setStatusTip("Redo")

        self.actCopy = QAction(QIcon("icons/copy.png"), "&Copy", self)
        self.actCopy.setShortcut("Ctrl+C")
        self.actCopy.setStatusTip("Copy")

        self.actCut = QAction(QIcon("icons/cut.png"), "Cu&t", self)
        self.actCut.setShortcut("Ctrl+X")
        self.actCut.setStatusTip("Cut")

        self.actPaste = QAction(QIcon("icons/paste.png"), "&Paste", self)
        self.actPaste.setShortcut("Ctrl+V")
        self.actPaste.setStatusTip("Paste")

        self.actAbout = QAction(QIcon("icons/about.png"), "About...", self)
        self.actAbout.setStatusTip("About...")
        self.actAbout.triggered.connect(self.about)

    def createMenuBar(self):
        menuBar = self.menuBar()

        actFile1 = QAction(QIcon("icons/new.png"), "File-1.txt", self)
        actFile1.setStatusTip(actFile1.text())
        actFile2 = QAction(QIcon("icons/new.png"), "File-2.txt", self)
        actFile2.setStatusTip(actFile2.text())
        actFile3 = QAction(QIcon("icons/new.png"), "File-3.txt", self)
        actFile3.setStatusTip(actFile3.text())

        file = menuBar.addMenu("&File")
        file.addAction(self.actNew)
        file.addSeparator()
        file.addAction(self.actOpen)
        file.addAction(self.actSave)
        file.addSeparator()
        recentFiles = file.addMenu("Recent files")
        recentFiles.addAction(actFile1)
        recentFiles.addAction(actFile2)
        recentFiles.addAction(actFile3)
        file.addSeparator()
        file.addAction(self.actExit)

        edit = menuBar.addMenu("&Edit")
        edit.addAction(self.actUndo)
        edit.addAction(self.actRedo)
        edit.addSeparator()
        edit.addAction(self.actCopy)
        edit.addAction(self.actCut)
        edit.addAction(self.actPaste)

        helpMenu = menuBar.addMenu("&Help")
        helpMenu.addAction(self.actAbout)

    @Slot()
    def newDocument(self):
        print("New document is requested")

    @Slot()
    def openDocument(self):
        filename, selectedFilter = QFileDialog.getOpenFileName(self, "Open file", ".")
        print(filename, selectedFilter)

    @Slot()
    def about(self):
        QMessageBox.information(self, self.windowTitle(), "MenuBar Sample V1.0")


if __name__ == "__main__":
    app = QApplication(sys.argv)
    myWindow = MyWindow()
    myWindow.show()
    sys.exit(app.exec())
La correction de l'exercice.

Et voici le résultat produit par cet exemple.

Enrichissement de votre barre de menu.


Définition d'actions Qt Définition d'un menu réutilisable