Accès rapide :
La vidéo
Il faut penser « réutilisabilité »
Gestion dynamique des thèmes
Le code de notre menu de sélection de thèmes
Cette vidéo vous montre comment coder une nouvelle classe de menu déroulant réutilisable. A titre d'exemple, vous allez réaliser un menu déroulant permettant de choisir le thème graphique à appliquer à l'application en cours d'exécution.
Une pratique qui me semble très saine consiste à toujours se demander si une partie du code à produire pourrait être réutilisable. Si tel est le cas, il faut alors arriver à extraire ce code dans un fichier plus facilement réutilisable.
Imaginons que pour votre application vous souhaitiez offrir un menu déroulant de changement de thème graphique. Après réflexion, une telle chose pourrait être réemployer sur d'autres développements. Du coup, autant coder une classe de menu réutilisable. C'est ce que nous allons tenter de faire dans ce chapitre.
Pour fonctionner, notre menu va scruter le contenu d'un dossier QSS : si des fichiers d'extension .qss
y sont présents, ils seront
alors considérés par notre menu déroulant.
Pour localiser les fichiers QSS je vais utiliser la méthode os.listdir
ainsi
qu'une liste en compréhension.
1 2 3 4 |
# On liste les fichiers d'extension .qss présents dans le dossier qss. styleSheets = [file for file in os.listdir("./qss") if file.endswith(".qss")] # On trie la liste sans tenir compte de la casse. styleSheets.sort(key=lambda file: file.lower()) |
Chaque fichier sélectionné par ce code devra produire une action dans notre menu déroulant. Pour ce faire, nous allons créer la méthode
createThemeAction
dans notre classe de menu déroulant.
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 |
import os import platform from PySide6.QtCore import QFile, QTextStream, Slot from PySide6.QtGui import QAction from PySide6.QtWidgets import QMenu, QStyleFactory, QApplication class ThemeMenu(QMenu): def __init__(self, text="&Themes", parent=None): super().__init__(text, parent) # On liste les fichiers d'extension .qss présents dans le dossier qss. styleSheets = [file for file in os.listdir("./qss") if file.endswith(".qss")] # On trie la liste sans tenir compte de la casse. styleSheets.sort(key=lambda file: file.lower()) # Pour chaque fichier trouvé, on crée l'action associée. for styleSheet in styleSheets: self.addAction(self.createThemeAction(styleSheet.replace(".qss", ""))) if len(styleSheets) > 0: self.addSeparator() # On récupère le theme de démarrage app = QApplication.instance() currentTheme = app.style().name() actFusion = QAction("&Fusion theme", self) actFusion.setStatusTip("Fusion theme") actFusion.setData("Fusion") actFusion.triggered.connect(self.changeTheme) actFusion.setCheckable(True) actFusion.setChecked(currentTheme == "fusion") self.addAction(actFusion) actWindows = QAction("&Windows theme", self) actWindows.setStatusTip("Windows theme") actWindows.setData("Windows") actWindows.triggered.connect(self.changeTheme) actWindows.setCheckable(True) actWindows.setChecked(currentTheme == "windows") self.addAction(actWindows) if platform.system() == "Windows": actWindowsVista = QAction("Windows &Vista theme", self) actWindowsVista.setStatusTip("Windows theme") actWindowsVista.setData("WindowsVista") actWindowsVista.triggered.connect(self.changeTheme) actWindowsVista.setCheckable(True) actWindowsVista.setChecked(currentTheme == "windowsvista") self.addAction(actWindowsVista) def createThemeAction(self, themeName): action = QAction(f"{themeName} theme", self) action.setStatusTip(f"{themeName} theme") action.setData(f"qss/{themeName}.qss") action.triggered.connect(self.changeStyleSheet) action.setCheckable(True) return action def checkSelectedAction(self): for action in self.actions(): if action != self.sender(): action.setChecked(False) @Slot() def changeStyleSheet(self): self.checkSelectedAction() qssFileName = self.sender().data() app = QApplication.instance() file = QFile(qssFileName) file.open(QFile.ReadOnly | QFile.Text) stream = QTextStream(file) app.setStyle(None) app.setStyleSheet(stream.readAll()) file.close() print(f"{qssFileName} applied") @Slot() def changeTheme(self): self.checkSelectedAction() themeName = self.sender().data() app = QApplication.instance() app.setStyleSheet(None) app.setStyle(QStyleFactory.create(themeName)) print(f"{themeName} style applied") |
Il ne reste plus qu'à inclure notre menu déroulant dans une fenêtre Qt.
1 2 3 4 5 |
menuBar = self.menuBar()
# Injection des autres menus déroulants de la barre
menuBar.addMenu(ThemeMenu())
|
Et voici le résultat produit.
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 :