Accès rapide :
Quelques précisions sur la notion de barres d'outils
Création d'une barre d'outils
Configurer le placement de votre barre d'outils
Configurer la flottaison
Configurer la possibilité de ré-ancrer une barre d'outils
Configurer les côtés sur lesquels une barre peut s'ancrer
Interconnexion avec la barre de statuts
Ajouter des séparateurs dans une barre d'outils
Connecter les slots à votre barre d'outils
Cas de l'utilisation d'une action QT (QAction)
Cas de l'utilisation d'un widget
Injecter plusieurs barres d'outils dans votre application
Travaux pratiques
L'énoncé de l'exercice
La correction de l'exercice
Par abus de langage, on parle de la barre d'outils d'une application. Mais en fait, cela est faux : une application peut proposer plusieurs barres d'outils. A titre d'exemple, voici une capture d'écran présentant une application avec trois barres d'outils (notez la présence du « gripper » devant chaque barre : il permet de les déplacer).
Ces barres sont souvent injectées ensembles juste en dessous de la barre de menu, d'où l'abus de langage. Pour rappel, voici un diagramme montrant la topologie classique d'une application graphique en mode « Bureau » (en mode « Desktop »).
Mais là aussi, il y a encore un petit mensonge. En réalité chaque barre d'outils peut être ancrée sur n'importe quel côté de la zone centrale, comme le
montre la capture d'écran suivante. La fenêtre contient en interne une instance de la classe
QDockWidget
: c'est elle qui définit les quatre points d'ancrage.
A l'instar d'une barre de menu, une barre d'outils peut se définir à partir d'actions. Ces actions, sont d'ailleurs souvent partagées entre la barre de menu et les barres d'outils. Mais cela n'est pas non plus une obligation : dans la capture d'écran précédente, vous pouvez observer une barre d'outils contenant directement des widgets Qt (un bouton et une case à cocher).
Le conteneur de barre d'outils est déjà instancié dans une QMainWindow
.
Par contre, vous devez demander la production d'une nouvelle barre d'outils via la méthode
addToolBar
. Par défaut, la nouvelle barre d'outils sera
ajoutée juste en dessous de la barre de menu et au-dessus de la zone centrale. Une barre d'outils possède un nom : il sera utilisé dans le menu contextuel
permettant de cacher/afficher la barre.
1 2 3 4 5 6 7 8 9 |
# Création de la barre d'outils avec son nom toolbar = self.addToolBar("First tool bar") # self représente la fenêtre de type QMainWindow # Ajout d'une action dans la barre d'outils. actNew = QAction(QIcon("icons/new.png"), "&New", self) toolbar.addAction(actNew) # Ajout d'un widget quelconque dans la barre d'outils. toolbar.addWidget(QPushButton("A button")) |
La capture d'écran ci-dessous affiche le menu contextuel pour cache/afficher une barre d'outils. Vous pouvez l'obtenir en cliquant avec le bouton droit de la souris sur la barre.
Si vous garder le bouton gauche de la souris appuyé sur le gripper à gauche de la barre d'outils (voir capture ci-dessous), vous devriez pouvoir l'ancrer sur un autre côté ou carrément détacher la barre de la fenêtre (la rendre flottante).
Si vous souhaitez interdire, ou non, la flottaison de votre barre d'outils, vous devez invoquer la méthode
setFloatable
(la valeur par défaut est True
).
1 |
toolbar.setFloatable(False)
|
Si vous souhaitez interdire, ou non, la possibilité d'ancrer la barre d'outils sur un autre côté de la fenêtre, vous devez utiliser la méthode
setMovable
(la valeur par défaut est True
).
1 |
toolbar.setMovable(False)
|
Vous pouvez aussi directement créer et positionner votre barre d'outils sur un côté précis. Pour ce faire, il faut légèrement changer le code :
vous devez d'abord produire l'instance de la barre d'outils. Elle sera de type
QToolBar
. Puis il vous faudra invoquer la méthode
addToolBar
en spécifiant en premier paramètre la
position de la barre et en second paramètre l'instance de la barre d'outils.
addToolBar
avec la position et le nom de la barre d'outils à produire (c'est bien dommage).
1 2 |
toolbar = QToolBar("First tool bar")
self.addToolBar(Qt.LeftToolBarArea, toolbar)
|
Enfin, si votre barre d'outils peut être déplacée (si elle est « movable »), alors vous pouvez limiter les côtés sur lesquels elle pourra s'accrocher. L'exemple suivant propose une barre d'outils positionnée à gauche par défaut, mais qui pourra être ancrée que latéralement (à gauche ou à droite).
1 2 3 |
toolbar = QToolBar("First tool bar")
self.addToolBar(Qt.LeftToolBarArea, toolbar)
toolbar.setAllowedAreas(Qt.LeftToolBarArea | Qt.RightToolBarArea)
|
Nous l'avons déjà vu : si votre barre d'outils utilise des actions, alors en cas de survol de la souris sur les éléments de la barre, le
statusTip
associé sera affiché dans la barre de statuts. A titre de rappel, voici comment spécifier le statusTip
d'une action Qt.
1 2 3 |
actNew = QAction(QIcon("icons/new.png"), "&New", self) actNew.setStatusTip("New file") toolbar.addAction(actNew) |
Et voici le résultat produit en cas de survol de la souris sur l'action associée.
Si vous placez des widgets dans vos barres d'outils, il est quand même possible d'avoir le même comportement.
Pour ce faire, il faut invoquer la méthode setStatusTip
sur votre widget.
1 2 3 |
button = QPushButton("A button") button.setStatusTip("It also works") toolbar.addWidget(button) |
A l'instar d'une barre de menu, il est possible d'ajouter des séparateurs dans une barre d'outils.
Pour ce faire, vous devez invoquer la méthode addSeparator
sur votre barre d'outils.
1 2 3 4 5 6 7 8 9 10 11 12 |
# Ajout d'une action dans la barre d'outils. actNew = QAction(QIcon("icons/new.png"), "&New", self) actNew.setStatusTip("New file") toolbar.addAction(actNew) # Ajout d'un séparateur toolbar.addSeparator() # Ajout d'un widget quelconque dans la barre d'outils. button = QPushButton("A button") button.setStatusTip("It also works") toolbar.addWidget(button) |
Pour connecter un slot aux éléments graphiques de votre barre d'outils, on procède de manière classique et habituelle. Deux situations sont à considérer : soit vous avez une action placée dans la barre d'outils, soit vous avez un widget.
Pour rappel, vous devez connecter le signal triggered
de votre action sur votre slot pour réagir à son l'activation
(par le clavier ou la souris).
1 2 3 4 |
actNew = QAction(QIcon("icons/new.png"), "&New", self) actNew.setStatusTip("New file") actNew.triggered.connect(self.newFile) toolbar.addAction(actNew) |
Pour ce qui est de vos widgets, il faudra en premier lieu déterminer sur quel signal vous souhaitez réagir (widget par widget).
Ensuite, utilisez la méthode connect
du signal pour le lier à votre slot. Voici un exemple réagissant au clic sur un bouton.
1 2 3 4 |
button = QPushButton("A button") button.setStatusTip("It also works") button.clicked.connect(self.buttonSlot) toolbar.addWidget(button) |
En synthèse, voici un exemple de code montrant un bon nombre de possibilités présentées depuis le début de ce document.
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 |
import sys from PySide6.QtCore import Slot from PySide6.QtGui import QIcon, QAction, Qt from PySide6.QtWidgets import QApplication, QMainWindow, QPushButton, QCheckBox class MyWindow(QMainWindow): def __init__(self): QMainWindow.__init__(self) self.setWindowTitle('ToolBars with Python/Qt') self.resize(400, 150) # Création de la barre d'outils avec son nom toolbar = self.addToolBar("First tool bar") toolbar.setAllowedAreas(Qt.TopToolBarArea | Qt.BottomToolBarArea) toolbar.setFloatable(False) # toolbar.setMovable(False) # Ajout d'une action dans la barre d'outils. actNew = QAction(QIcon("icons/new.png"), "&New", self) actNew.setStatusTip("New file") actNew.triggered.connect(self.newFile) toolbar.addAction(actNew) # Ajout d'un séparateur toolbar.addSeparator() # Ajout d'un widget quelconque dans la barre d'outils. button = QPushButton("A button") button.setStatusTip("It also works") button.clicked.connect(self.buttonSlot) toolbar.addWidget(button) # On demande l'instanciation de la barre de status self.statusBar().showMessage("ToolBar sample") @Slot() def newFile(self): print("New file requested") @Slot() def buttonSlot(self): print("Button clicked") if __name__ == "__main__": app = QApplication(sys.argv) myWindow = MyWindow() myWindow.show() sys.exit(app.exec()) |
Vous pouvez ajouter autant de barres d'outils que nécessaire dans votre application. Pour ce faire, il vous suffit de répéter autant d'appels que souhaité
à la méthode addToolBar
. Ensuite veuillez remplir chaque
barre d'outils avec les éléments requis.
Voici une capture d'écran montrant une fenêtre avec une barre de menu, trois barres d'outils et une barre de status. En vous basant sur les explications de ce chapitre, mais aussi celles des chapitres précédents (en notamment ceux sur les actions et les barre de menu), veuillez développer un programme affichant, à peu près, les mêmes éléments.
Comme toujours, essayez de réaliser l'exercice sans directement copier/coller le code ci-dessous. ;-)
Voici ma proposition de 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 120 121 122 123 124 125 |
import sys from PySide6.QtCore import Slot from PySide6.QtGui import QIcon, QAction, Qt from PySide6.QtWidgets import QApplication, QMainWindow, QToolBar, QPushButton, QCheckBox, QComboBox class MyWindow(QMainWindow): def __init__(self): super().__init__() self.setWindowTitle("Exemple de définition de barres d'outils Qt") self.setWindowIcon(QIcon("icons/file.png")) self.resize(600, 150) self.createActions() self.createMenuBar() self.createToolBars() statusBar = self.statusBar() statusBar.showMessage(self.windowTitle()) # Définition du message initial # Les actions seront communes à la barre de menu et aux barres d'outils # C'est pour cette raison qu'elles sont stockées sous forme d'attributs : # on pourra les retrouver plus rapidement. 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) 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 selection") self.actCut = QAction(QIcon("icons/cut.png"), "Cu&t", self) self.actCut.setShortcut("Ctrl+X") self.actCut.setStatusTip("Cut selection") 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 this application") 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) 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) help = menuBar.addMenu("&Help") help.addAction(self.actAbout) def createToolBars(self): file = self.addToolBar("File tool bar") file.addAction(self.actNew) file.addSeparator() file.addAction(self.actOpen) file.addAction(self.actSave) file.addSeparator() file.addAction(self.actExit) edit = self.addToolBar("Edit tool bar") edit.addAction(self.actUndo) edit.addAction(self.actRedo) edit.addSeparator() edit.addAction(self.actCopy) edit.addAction(self.actCut) edit.addAction(self.actPaste) bottomToolbar = QToolBar("Bottom tool bar") self.addToolBar(Qt.BottomToolBarArea, bottomToolbar) bottomToolbar.addWidget(QPushButton("A button")) bottomToolbar.addWidget(QCheckBox("A check box")) comboBox = QComboBox() comboBox.addItems(["A combo box with some choices", "Other choice"]) bottomToolbar.addWidget(comboBox) @Slot() def newDocument(self): print("New document is requested") 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 :