Guide de l'utilisateur - Bibliothèque CWidgets V0.1.0a1 :
CWidgets : Votre puissance en programmation sans limites
Transformez les obstacles Qt en opportunités créatives
CWidgets est une bibliothèque Python spécialisée qui donne aux développeurs malvoyants un contrôle total sur les interfaces PyQt6 et PySide6.
L'ère des limitations avec QTextEdit est révolue. Désormais, vous pouvez concevoir des interfaces avec des zones de texte multi-lignes en toute liberté et compatibilité.
La bibliothèque offre une compatibilité absolue pour les développeurs malvoyants, car tous les éléments sont conçus pour fonctionner parfaitement avec le lecteur d'écran NVDA.
Créativité continue : Pas besoin d'apprendre de nouveaux outils, continuez simplement à écrire le code auquel vous êtes habitué tout en conservant les mêmes fonctions et caractéristiques.
Ingénierie intelligente : Chaque élément de CWidgets hérite des propriétés des éléments Qt originaux, garantissant des performances standard avec des solutions radicales aux problèmes de compatibilité.
Qu'est-ce qui changera dans la façon dont vous écrivez vos programmes en utilisant les fenêtres PyQT6 et PySide6 ?
Tout ce que vous devez faire est de remplacer la première lettre seulement (C au lieu de Q) :
CTextEdit au lieu de QTextEdit.
CButton au lieu de QPushButton.
Où C signifie Custom (personnalisé) ou customized.
Flexibilité totale dans le travail, car la bibliothèque supporte votre environnement de travail préféré avec la même efficacité :
Avec PySide6 : from cwidgets.pyside6 import CButton, CLabel, CLineEdit.... Avec PyQt6 : from cwidgets.pyqt6 import CButton, CLabel, CLineEdit .....
CWidgets : Codez en toute confiance, concevez sans limites.
7 éléments personnalisés entièrement compatibles fournis par cette bibliothèque :
pip install cwidgets
Après l'installation, commencez à explorer la bibliothèque, ses composants, propriétés et leur utilisation grâce à ces fonctions :
import cwidgets # Lister tous les composants disponibles cwidgets.widgets() # Lister toutes les sections disponibles cwidgets.sections() # Ouvrir le guide complet dans le navigateur cwidgets.show_help() cwidgets.show_help(lang="fr") # Ouvrir un composant spécifique directement cwidgets.show_help(lang="fr", goto="CButton") cwidgets.show_help(lang="fr", goto="CTextEdit") # Ouvrir une section spécifique directement cwidgets.show_help(lang="fr", goto="introduction") cwidgets.show_help(lang="fr", goto="installation")
#CTextEdit : Zone de texte multi-lignes : CTextEdit résout le problème fondamental de QTextEdit, qui est incompatible avec NVDA.
#CComboBox & CListWidget : Séparation de la navigation et de l'activation : Séparer les actions de navigation (flèches) des actions d'activation (Entrée/Espace) pour éviter les activations involontaires. Désactivation disponible : Maintien de l'annonce par NVDA même lorsque le composant est désactivé.
#CButton : Activation avec ENTRÉE, RETOUR, ESPACE et la souris. Compatibilité même en cas de désactivation.
#CLabel : Compatibilité améliorée pour les titres et étiquettes
#CLineEdit : Permet de récupérer le texte depuis l'élément en appuyant sur Entrée sans aucun code supplémentaire.
#CMessageBox : Boîtes de dialogue de message à fermeture automatique. Vous pouvez spécifier un délai après lequel la boîte de dialogue disparaît automatiquement.
#À l'exception de CTextEdit, tous les autres composants héritent de QT et conservent donc toutes leurs propriétés et fonctions de base.
Définition, création, propriétés, utilisation.
CTextEdit est une zone de texte multi-lignes entièrement compatible avec NVDA.
C'est la barrière qui empêche les développeurs malvoyants de concevoir des interfaces QT contenant des zones de texte multi-lignes.
Jusqu'à l'apparition de cette bibliothèque, aucune solution à ce problème n'était connue pour être utilisée par les développeurs malvoyants.
La solution apportée par cette bibliothèque est d'intégrer un contrôle Win32 RichEdit directement dans la fenêtre QT.
Win32 RichEdit est entièrement compatible avec NVDA par défaut.
La phase complexe dans la conception de la solution est son intégration dans une fenêtre Qt tout en maintenant cette accessibilité.
Cette bibliothèque a également assuré l'utilisation par défaut des commandes dans QT.
Structure de l'élément QTextEdit :
-QTextEdit
-EditorStyle — Styles, police, couleur, alignement
-RichEdit Win32 — Le moteur original compatible
# PySide6
from cwidgets.pyside6 import CTextEdit
# PyQt6
from cwidgets.pyqt6 import CTextEdit
# Création
self.editor = CTextEdit(self, accessible_name="Nom de la zone")
layout.addWidget(self.editor)
# Insérer du texte dans la zone
self.editor.setText("Bonjour !")
# Récupérer le texte de la zone :
text = self.editor.text()
text = self.editor.toPlainText()
# Ajouter du texte au texte original
self.editor.append("Nouvelle ligne.")
# Effacer le texte pour vider la zone
self.editor.clear()
# Rendre la zone en lecture seule
self.editor.setReadOnly(True)
# Désactiver la lecture seule pour rendre la zone modifiable et lisible
self.editor.setReadOnly(False)
# Police — QFont ou (str, int, bool, bool)
self.editor.setFont("Arial", 12, True, False) # Nom, taille, gras, italique
# Couleurs — nom ou ensemble RGB
self.editor.setTextColor("red")
self.editor.setTextColor((255, 0, 0))
self.editor.setBackgroundColor("yellow")
# Alignement
self.editor.setAlignment("left")
self.editor.setAlignment("center")
self.editor.setAlignment("right")
# Noms supportés
"black", "white", "red", "green", "blue", "yellow",
"cyan", "magenta", "gray", "darkgray", "lightgray",
"orange", "purple", "violet", "pink", "brown",
"navy", "teal", "lime", "olive", "maroon",
"coral", "salmon", "gold", "silver"
# ou ensemble RGB
(255, 0, 0) # rouge
(0, 128, 255) # bleu clair
accessible_name est lu par NVDA mais n'est pas visible visuellement.
Pour ajouter un titre visuel, ajoutez un CLabel au layout avant l'éditeur :
self.editor = CTextEdit(self)
self.lbl = CLabel("Zone d'édition :", self, self.editor)
Il est essentiel de noter que l'ajout de CLabel au layout doit précéder l'ajout de l'éditeur pour que le nom de la zone apparaisse au-dessus de la zone et non en dessous.
layout.addWidget(self.lbl)
layout.addWidget(self.editor)
CLabel est une étiquette compatible avec NVDA qui remplace QLabel.
Le QLabel original est invisible pour NVDA sauf s'il est lié à un buddy — et seulement lorsque ce buddy a le focus.
Deux modes :
- Mode simple : Compatible avec NVDA et reconnu même avec la navigation par tabulation.
- Mode Buddy : Lorsque CLabel est lié à un autre élément.
# PySide6
from cwidgets.pyside6 import CLabel, CLineEdit
# PyQt6
from cwidgets.pyqt6 import CLabel, CLineEdit
# Mode simple — NVDA lit le texte et peut être accédé via tabulation :
self.lbl = CLabel("Fichier enregistré", self)
# Avec prefix — NVDA annonce : "statut Fichier enregistré"
self.lbl = CLabel("Fichier enregistré", self, prefix="statut")
# Mode Buddy — NVDA annonce l'étiquette lorsque le champ obtient le focus
# L'étiquette doit être ajoutée au layout avant le champ de saisie pour que l'étiquette apparaisse visuellement au-dessus du champ
self.edit = CLineEdit(self)
self.lbl = CLabel("Nom :", self, self.edit)
layout.addWidget(self.lbl)
layout.addWidget(self.edit)
# Mise à jour dynamique
self.lbl.setText("Traitement en cours")
self.lbl.setPrefix("Erreur")
CButton est un bouton avec des fonctionnalités supplémentaires qui le rendent utilisable sans avoir besoin de lignes de code supplémentaires que le bouton original nécessiterait pour activer ces fonctionnalités.
# PySide6
from cwidgets.pyside6 import CButton
# PyQt6
from cwidgets.pyqt6 import CButton
self.btn = CButton("Enregistrer", self)
self.btn.clicked.connect(self.on_click)
# Désactiver — NVDA annonce "indisponible", le bouton n'est pas cliquable
self.btn.setEnabled(False)
self.btn.setEnabled(True)
# Changer le titre — Qt original
self.btn.setText("Nouveau titre")
# Vérifier l'état
if self.btn.isEnabled():
...
CLineEdit est un champ de saisie de texte compatible qui remplace QLineEdit.
QLineEdit nécessite une ligne de code supplémentaire pour récupérer le texte.
CLineEdit rend cette activation automatique via le signal validated.
# PySide6
from cwidgets.pyside6 import CLineEdit, CLabel
# PyQt6
from cwidgets.pyqt6 import CLineEdit, CLabel
# Créer le champ en premier pour le buddy
self.edit = CLineEdit(self)
self.lbl = CLabel("Nom :", self, self.edit)
layout.addWidget(self.lbl)
layout.addWidget(self.edit)
# Avec texte initial
self.edit = CLineEdit(self, "Le Caire")
# Avec texte d'espace réservé
self.edit = CLineEdit(self, placeholderText="Entrez votre nom...")
# Signal validated
self.edit.validated.connect(self.on_validated)
def on_validated(self, text):
print(text)
# Afficher/masquer — Qt original
self.edit.hide()
self.edit.show()
CComboBox est une liste déroulante compatible qui remplace QComboBox.
Le QComboBox original est activé en interne par les flèches.
C'est un problème pour les utilisateurs malvoyants qui naviguent avec les flèches.
Séparation explicite entre la navigation et l'activation.
Tout en maintenant la compatibilité même lorsque la liste est désactivée.
# PySide6
from cwidgets.pyside6 import CComboBox, CLabel, CMessageBox, CButton
# PyQt6
from cwidgets.pyqt6 import CComboBox, CLabel, CMessageBox, CButton
# Créer la liste en premier pour le buddy
self.combo = CComboBox(self)
self.combo.addItems(["Égypte", "Tunisie", "Maroc"])
self.lbl = CLabel("Liste des pays :", self, self.combo)
layout.addWidget(self.lbl)
layout.addWidget(self.combo)
self.combo.validated.connect(self.on_selection)
self.combo.cleared.connect(self.on_cleared)
# Bouton pour vider la liste
self.btn_clear = CButton("Vider", self)
self.btn_clear.clicked.connect(self.combo.clear)
def on_selection(self):
text = self.combo.currentText()
index = self.combo.currentIndex()
CMessageBox.information(self, "Sélection", f"Pays : {text}")
def on_cleared(self):
CMessageBox.warning(self, "Avertissement", "Aucun élément disponible dans la liste.")
# Désactiver / réactiver
self.combo.setEnabled(False)
self.combo.setEnabled(True)
CListWidget est une liste compatible qui remplace QListWidget.
Le QListWidget original est activé immédiatement lors de la navigation avec les flèches.
C'est un obstacle pour les utilisateurs malvoyants, et désactiver cette activation avec les flèches nécessite l'écriture de lignes de code supplémentaires.
# PySide6
from cwidgets.pyside6 import CListWidget, CLabel
# PyQt6
from cwidgets.pyqt6 import CListWidget, CLabel
# Créer la liste
self.list = CListWidget(self)
self.list.addItems(["Irak", "Arabie Saoudite", "Koweït"])
self.lbl = CLabel("Liste des pays :", self, self.list)
layout.addWidget(self.lbl)
layout.addWidget(self.list)
# Signal Qt original — correspondant à QListWidget
self.list.itemActivated.connect(self.on_item)
def on_item(self, item):
text = item.text()
row = self.list.currentRow()
print(row, text)
# Désactiver / réactiver
self.list.setEnabled(False)
self.list.setEnabled(True)
# Vider — Qt original
self.list.clear()
CMessageBox est une boîte de dialogue de message compatible.
Le QMessageBox original ne fournit pas de fermeture automatique.
Il est nécessaire pour les messages qui ne nécessitent pas d'intervention de l'utilisateur.
Ajout d'un mode où le message se ferme après un temps spécifié.
# PySide6
from cwidgets.pyside6 import CMessageBox
# PyQt6
from cwidgets.pyqt6 import CMessageBox
# Information non temporisée
CMessageBox.information(self, "Succès", "Fichier enregistré.")
# Information temporisée — fermeture automatique après 3 secondes
CMessageBox.information(self, "Succès", "Fichier enregistré.", timeout=3000)
# Avertissement non temporisé
CMessageBox.warning(self, "Avertissement", "Espace disque insuffisant.")
# Avertissement temporisé
CMessageBox.warning(self, "Avertissement", "Connexion instable.", timeout=4000)
# Erreur — non temporisé + son — fermeture manuelle obligatoire
CMessageBox.critical(self, "Erreur", "Fichier introuvable.")
# Il est recommandé d'utiliser le délai uniquement pour information et warning
# Le délai n'est pas disponible pour critical
# Non recommandé — remplace le label
self.combo.setAccessibleName("...")
# Correct
self.lbl = CLabel("Liste des pays :", self, self.combo)
# Correct — l'élément est créé avant l'étiquette
self.combo = CComboBox(self)
self.lbl = CLabel("Pays :", self, self.combo)
Fournis par la bibliothèque :
- validate_parent — Vérification régulière de la fenêtre parent
- logger — Journalisation des erreurs (module "cwidgets")
Mohamed Hédi Bettaieb (Tunisie)
Contact : hedidouz@gmail.com
Date de conception : Mai 2026
Ce projet vise à rendre les applications Qt accessibles à 100% pour les développeurs et utilisateurs malvoyants, sans sacrifier la productivité ou les habitudes des développeurs Qt.