Blog ENI : Toute la veille numérique !
En raison d'une opération de maintenance, le site Editions ENI sera inaccessible le mardi 10 décembre, en début de journée. Nous vous invitons à anticiper vos achats. Nous nous excusons pour la gêne occasionnée
En raison d'une opération de maintenance, le site Editions ENI sera inaccessible le mardi 10 décembre, en début de journée. Nous vous invitons à anticiper vos achats. Nous nous excusons pour la gêne occasionnée
  1. Livres et vidéos
  2. PyQt5
  3. Gestion des styles et des apparences en PyQt
Extrait - PyQt5 Développez vos interfaces graphiques en Python
Extraits du livre
PyQt5 Développez vos interfaces graphiques en Python
4 avis
Revenir à la page d'achat du livre

Gestion des styles et des apparences en PyQt

Introduction

Le chapitre précédent utilisait, avant même que nous l’abordions ici, un aspect de la gestion des styles, ceci avec la ligne suivante. Nous appliquions alors un style à une instance de widget en imposant le noir comme couleur de fond de cette instance.

self.lcd.setStyleSheet('background-color:black;') 

Cette ligne nous fournit plusieurs informations : PyQt supporte les feuilles de style et donc manipule quelque chose de semblable à CSS (Cascading Style Sheets). Le CSS est une technologie permettant de définir la présentation d’une page HTML et qui est, à ce titre, un aspect central des normes du Web moderne. Pour Qt, il ne s’agit pas de CSS mais de QSS (Qt Style Sheets) dont le fonctionnement est très similaire.

Dans le présent chapitre :

  • nous allons continuer à apprendre à utiliser les polices de caractères, les images et les icônes, afin d’embellir nos applications PyQt ;

  • de manière plus générale, nous nous intéresserons à la gestion des ressources en PyQt ;

  • nous détaillerons ensuite l’utilisation de QPalette, de QBrush, puis des feuilles de style en PyQt. Nous découvrirons ainsi QSS (Qt Style Sheets) ;

  • nous apprendrons enfin à créer nos propres styles pour PyQt.

Pour assimiler pas à pas les différents aspects étudiés...

Manipuler les polices, l’objet QFont

1. Utiliser l’objet QFont

La documentation en ligne de l’objet QFont est disponible à cette adresse : https://doc.qt.io/qt-5/qfont.html

L’objet QFont permet d’encapsuler le nom de la police choisie, sa taille, son style éventuel (gras, italique, etc.), son étirement, la dimension des espaces entre chaque caractère et bien d’autres paramètres encore. 

Pour l’utiliser, on commence par déclarer l’import adéquat.

from PyQt5.QtGui import QFont 

On instancie ensuite l’objet de type QFont, par exemple selon les lignes de code ci-dessous. On déclare la police de nom Chalkduster, en taille 18 et avec une stylisation en gras. On active également la mise en italique.

maFont = QFont('Chalkduster', 18, QFont.Bold) 
maFont.setItalic(True) 

Une fois notre police PyQt créée, on peut l’utiliser sur nos différents widgets grâce à la méthode en général disponible setFont.

Ainsi, en reprenant l’exemple précédent, on change la police du label du champ « Nom : » (lignes concernées en gras).

import sys 
from PyQt5.QtWidgets import QApplication, QWidget, QPushButton, QCheckBox 
from PyQt5.QtWidgets import QFormLayout, QLabel, QLineEdit, QcomboBox 
 
from PyQt5.QtGui import QFont 
 
maFont = QFont('Chalkduster', 18, QFont.Bold) 
maFont.setItalic(True) 
 
class Fenetre(QWidget): 
 
    def __init__(self): 
 
        super().__init__() 
 
        self.setGeometry(100, 100, 250, 100) 
        self.setWindowTitle("Chapitre 6 - formulaire") 
        self.disposition = QFormLayout() 
 
        self.nomLabel = QLabel("Nom : ") 
        self.nom = QLineEdit() 
        self.disposition.addRow(self.nomLabel, self.nom) 
 
        self.prenomLabel = QLabel("Prénom : ") 
        self.prenom...

Manipuler les images en PyQt

1. Utilisation de QPixmap pour les images

Nous avons déjà évoqué la mise en place et l’insertion d’images dans une interface utilisateur développée en PyQt. Dans cette section, nous allons toutefois approfondir la question.

La documentation en ligne Qt de la classe QPixmap se trouve à cette adresse : https://doc.qt.io/qt-5/qpixmap.html

Précisons que QPixmap permet de dessiner, tracer des figures et manipuler des couleurs.

Cette classe permet ici d’afficher une image au format JPEG, PNG ou même au format vectoriel (SVG). L’idée est en première approche de créer une instance que l’on affiche ensuite au sein d’un label (QLabel). C’est ainsi que l’on procède dans l’exemple suivant. L’instanciation prend en paramètre le chemin complet de l’image. Ici, l’image est stockée dans le répertoire courant du script Python :

self.logoLabel = QLabel("Logo : ") 
self.logo = QLabel() 
self.image = QPixmap('Logo_ENI.svg') 
self.logo.setPixmap(self.image) 
self.disposition.addRow(self.logoLabel, self.logo) 

On place ceci dans notre code exemple (lignes concernées en gras) :

import sys 
from PyQt5.QtWidgets import QApplication, QWidget, QPushButton, QCheckBox 
from PyQt5.QtWidgets import QFormLayout, QLabel, QLineEdit, QComboBox 
 
from PyQt5.QtGui import QFont, QfontInfo 
from PyQt5.QtGui import Qpixmap 
 
 
maFont = QFont() 
maFont.setFamily('Arial Black') 
maFont.setPointSize(15) ...

Manipuler les icônes en PyQt

1. Introduction

La gestion des icônes en PyQt utilise elle aussi la classe QPixmap. En effet, on définira plusieurs icônes grâce à la classe Qpixmap. Ces icônes formeront alors une collection d’icônes. Cette collection sera stockée dans une instance de la classe QIcon, instance que l’on associera à un widget. Chaque icône sera associée à un statut/mode ou à un état de ce widget.

La documentation en ligne de la classe QIcon est disponible ici : https://doc.qt.io/qt-5/qicon.html

2. Exemple d’utilisation

Dans cet exemple, on définit deux boutons, dont l’un sera normalement activé et l’autre sera désactivé (Disabled). On définit ensuite une collection d’icônes avec la classe QIcon. Dans cette collection, on définit une icône pour chaque état qui nous intéresse.

On commence par déclarer les imports.

from PyQt5.QtGui import QPixmap, QIcon 

Puis on instancie la classe QIcon dans laquelle on stocke des couples (QPixmapState). 

self.iconeCollection = QIcon() 
 
self.icone1 = QPixmap('gras.png') 
self.iconeCollection.addPixmap(self.icone1, QIcon.Disabled) 
 
self.icone2 = QPixmap('italique.png') 
self.iconeCollection.addPixmap(self.icone2, QIcon.Active) 

Ainsi, quand on définira...

Les fichiers de ressources en PyQt

1. Introduction

Les chemins que nous avons utilisés pour nos deux icônes, dans l’exemple précédent, sont déclarés en chemin relatif. Cela signifie que leurs positions sur le disque sont déclarées de manière non absolue en prenant comme référence l’emplacement du programme Python sur le disque.

Cela n’est pas nécessairement un problème ; toutefois, si l’on déplace les fichiers images de nos icônes, ou si l’on déplace le fichier Python lui-même, le programme ne saura plus où trouver les fichiers images, qui n’apparaîtront alors pas (il n’y a pas de déclenchement d’erreur dans ce cas).

Pour pallier cette fragilité, il est possible dans certaines technologies de définir des fichiers de ressources incluant l’emplacement des ressources (qui peuvent être des images, des icônes, mais également des sons ou des fichiers de traductions). C’est le cas par exemple en développement Microsoft .NET. C’est également le cas en PyQt qui offre une solution de gestion des fichiers de ressources, dans la mesure où Qt offre cette possibilité.

2. Ressources et PyQt

Cette solution consiste à créer un fichier de ressources d’extension .qrc. Cette extension signifie Qt Resource Collection. Le contenu du fichier est formaté en un format de type XML. Ainsi, en reprenant l’exemple précédent au sujet de la manipulation d’icônes, nous pourrions utiliser le fichier QRC suivant :

<!DOCTYPE RCC> 
<RCC version="1.0"> 
<qresource> 
   <file alias="gras.png">gras.png</file> 
   <file alias="italique.png">italique.png</file> 
</qresource> 
</RCC> 

La prochaine étape est de générer un fichier Python de sortie relatif à notre fichier QRC. Pour cela, on utilise un exécutable dédié (nommé pyrcc5) qui nous permet de générer une sortie Python depuis une entrée QRC.

> pyrcc5 -o sortie.py QRC_exemple.qrc 

On obtient dans le répertoire dans lequel se trouve le fichier QRC (nommé dans notre exemple QRC_exemple.qrc)...

L’usage de QPalette en PyQt

1. Introduction

Quand on utilise une couleur en PyQt, on l’utilise dans un certain « contexte ». Outre la définition de la couleur, on peut également choisir le « lieu » d’application de cette couleur (est-ce un fond, une coloration de police ?). On voit que ces notions sont connexes et unifiables dans un objet englobant. C’est exactement l’utilité de QPalette que d’englober ainsi des informations relatives à l’usage d’une couleur en particulier.

La documentation Qt en ligne de QPalette est disponible à cette adresse : https://doc.qt.io/qt-5/qpalette.html

2. Utilisation de QPalette

Pour illustrer notre propos au sujet de l’usage d’une palette en PyQt, nous reprenons l’exemple d’une fenêtre de type formulaire simple.

On commence par ajouter les imports dont nous allons avoir besoin.

from PyQt5.QtCore import Qt 
 
from PyQt5.QtGui import QFont, QPalette, QColor 

Qt va nous permettre d’accéder à certaines couleurs. QColor propose une méthode de définition de couleur.

L’idée est à présent de définir deux palettes : l’une pour écrire le texte d’un bouton en bleu et l’autre pour écrire le texte en rouge. Évidemment, l’intérêt est de factoriser...

L’usage de QBrush en PyQt

1. Introduction

La classe ici utilisée est QBrush dont la documentation Qt en ligne est disponible à cette adresse : https://doc.qt.io/qt-5/qbrush.html

Manipuler des instances de QBrush implique parfois de lui associer un style de dégradé (Brush Style). Ces styles sont énumérés dans un objet de type énumération de Qt dont la documentation illustrée est disponible ici : https://doc.qt.io/qt-5/qt.html#BrushStyle-enum

L’usage de QBrush dans un QPalette est très similaire au cas précédent de définition de la couleur. En effet, en lieu et place de l’usage de la méthode setColor, nous utiliserons la méthode setBrush.

2. Utilisation de QBrush

Prenons un rapide exemple d’utilisation mettant en exergue la simplicité d’utilisation. Le but ici est de colorer en pointillé rouge le fond de notre fenêtre d’exemple.

On commence donc par modifier les imports pour pouvoir utiliser les classes dont nous aurons besoin.

from PyQt5.QtGui import QFont, QPalette, QColor, QBrush 

Puis nous définissons une instance de QBrush en précisant que nous souhaitons utiliser la couleur rouge ainsi qu’un effet pointillé un peu particulier (voir l’énumération évoquée précédemment à ce propos).

brush3 = QBrush(Qt.red, Qt.Dense3Pattern)...

La gestion des styles en PyQt

1. Introduction

L’usage de QPalette est un premier outil pour tendre vers une certaine « ré-utilisabilité » dans nos codes PyQt. On entend par ré-utilisabilité la capacité de définir certains aspects une fois pour toutes et s’éviter ainsi d’écrire deux fois la même chose.

Cette première étape est intéressante, mais d’une part elle n’est pas exhaustive (on ne peut pas tout faire avec cet outil) et d’autre part l’outil manque parfois de flexibilité (on associe explicitement la palette à un élément graphique).

Ces limites ainsi identifiées sont justement dépassées grâce à la gestion de styles en PyQt avec le QSS (Qt Style Sheets). Plus de puissance et de flexibilité, dans l’esprit même du CSS utilisé en développement HTML. Si vous avez déjà utilisé le CSS dans le cadre d’un développement web, vous retrouverez l’essentiel de ses préceptes dans le QSS que nous allons étudier ici.

2. Première utilisation de QSS

L’utilisation de QSS consiste à définir une feuille de style dans laquelle on précise la valeur d’une propriété relative à un widget donné, exactement comme en CSS on précise la valeur d’une propriété pour une balise HTML donnée. On a alors une syntaxe comme ci-dessous, tout à fait similaire à ce qui se fait en CSS, y compris en ce qui concerne les noms des propriétés.

[Le Widget ciblé] 
{ 
  [propriété]: [valeur de la propriété]; 
} 

De fait, si on veut colorer en rouge le fond de notre fenêtre d’exemple, on procédera selon les étapes suivantes.

On commencera par créer une chaîne de caractères avec pour la cible (ici QWidget) la propriété background-color à la couleur red.

feuille_de_style = "QWidget{ background-color: red; }" 

La feuille de style n’est pas très lisible présentée ainsi. Pour y remédier, on va organiser la feuille de style sur plusieurs lignes grâce à la syntaxe des trois...

Conclusion du chapitre

Ce chapitre nous a permis d’apprendre l’essentiel concernant la stylisation en PyQt et notamment l’usage des feuilles de style QSS.

On a relevé plusieurs remarques à propos de l’outil QSS.

Si l’outil QSS est indiscutablement puissant et doit voir son utilisation favorisée autant que possible, il y a deux limites à rappeler :

  • Les performances sur des applications de grande taille peuvent être altérées en partie à cause du système QSS.

  • Le CSS implémenté par QSS reste dans un stade relativement rudimentaire et ne fait par exemple pas intervenir Flexbox ou Media Queries et encore moins CSS Animations.

Pour prolonger le sujet de l’animation évoqué au point précédent, on note qu’il est tout à fait possible d’animer les interfaces développées en PyQt. Cet aspect sera l’objet du chapitre suivant.