Skip to main content

A chainable PySide6 UI wrapper for building desktop apps fast

Project description

UIWrapper — Documentation

Wrapper PyQt6 pensé pour construire des interfaces de bureau en Python de manière lisible, chainable, et sans répétition.


Table des matières

  1. Démarrage rapide
  2. UIWrapper | La fenêtre principale
  3. Section | Les zones de contenu
  4. Widgets de base
  5. Formulaires
  6. Mise en page
  7. Positionnement
  8. Sidebars
  9. Onglets
  10. Scroll
  11. Tables
  12. Références nommées
  13. Styling et thèmes
  14. Notifications
  15. Fenêtres secondaires
  16. Inspector
  17. Raccourcis et bonnes pratiques

Démarrage rapide

from ui.ui_tools import UIWrapper

def main():
    ui = UIWrapper(title="Mon App", width=800, height=600, padding=10)
    ui.load_style("style/style.qss")

    ui.sidebar("left", size=180, align="top") \
        .add_label("Navigation") \
        .add_spacing(10) \
        .add_button("Accueil", lambda: print("Accueil")) \
        .add_button("Paramètres", lambda: print("Paramètres"))

    ui.add_label("Bienvenue !") \
      .add_button("Cliquez ici", lambda: ui.notify("Bonjour !", "success"))

    ui.run()

if __name__ == "__main__":
    main()

UIWrapper

UIWrapper est le point d'entrée de toute interface. Il crée la fenêtre, gère les sidebars, le style et le cycle de vie de l'application.

Création

ui = UIWrapper(title="Mon App", width=800, height=600, padding=10)
Paramètre Type Défaut Description
title str "" Titre affiché dans la barre de fenêtre
width int 800 Largeur initiale en pixels
height int 600 Hauteur initiale en pixels
padding int 0 Marge intérieure globale en pixels

Gestion de la fenêtre

ui.run()

Lance l'application et affiche la fenêtre. À appeler en dernier, après avoir construit toute l'interface.

ui.run()

ui.center()

Centre la fenêtre sur l'écran. À appeler avant run().

ui.center()
ui.run()

ui.set_resizable(resizable)

Autorise ou bloque le redimensionnement de la fenêtre par l'utilisateur.

ui.set_resizable(False)   # fenêtre figée
ui.set_resizable(True)    # redimensionnable

ui.set_min_size(width, height) / ui.set_max_size(width, height)

Définit les dimensions minimales ou maximales de la fenêtre.

ui.set_min_size(400, 300)
ui.set_max_size(1920, 1080)

ui.set_opacity(value)

Modifie la transparence de la fenêtre. 1.0 = opaque, 0.0 = invisible.

ui.set_opacity(0.95)

ui.set_icon(path)

Définit l'icône affichée dans la barre de titre et la barre des tâches.

ui.set_icon("assets/icon.png")

ui.set_on_close(callback)

Déclenche une fonction quand l'utilisateur ferme la fenêtre.

ui.set_on_close(lambda: print("Au revoir !"))

ui.load_style(path)

Charge un fichier .qss (CSS Qt) et l'applique à toute la fenêtre.

ui.load_style("style/style.qss")

ui.open_window(title, width, height, padding)

Ouvre une fenêtre secondaire indépendante. Retourne un nouvel UIWrapper avec toute la même API disponible.

def ouvrir_aide():
    win = ui.open_window("Aide", width=400, height=300, padding=10)
    win.add_label("Bienvenue dans l'aide.")
    win.add_button("Fermer", lambda: win.window.close())

ui.add_button("Aide", ouvrir_aide)

ui.notify(text, kind, duration)

Affiche une notification flottante en bas de la fenêtre, qui disparaît automatiquement.

Paramètre Type Défaut Description
text str Texte affiché
kind str "info" Style : "success", "error", "warning", "info"
duration int 3000 Durée en millisecondes avant disparition
ui.notify("Sauvegardé !", "success")
ui.notify("Connexion perdue", "error", duration=5000)

Section

Une Section représente une zone de l'interface dans laquelle on ajoute des éléments. Toutes les méthodes retournent self ce qui permet le chaînage.

UIWrapper expose directement les méthodes de Section pour le contenu central — pas besoin d'y accéder explicitement.


Widgets de base

add_label(text, stretch, name)

Ajoute un texte non interactif.

ui.add_label("Bienvenue !")
ui.add_label("Titre important", name="titre-principal")

add_button(text, callback, stretch, gap, name)

Ajoute un bouton cliquable.

Paramètre Description
text Texte du bouton
callback Fonction appelée au clic
stretch Proportion de l'espace occupé (voir Positionnement)
gap Espace en pixels ajouté après le bouton
name Nom pour y accéder plus tard via get()
ui.add_button("Valider", lambda: print("ok"))
ui.add_button("Supprimer", on_delete, gap=10, name="btn-supprimer")

add_separator()

Ajoute une ligne de séparation visuelle. Horizontale dans une colonne, verticale dans une ligne.

ui.add_label("Section A")
ui.add_separator()
ui.add_label("Section B")

Formulaires

add_input(placeholder, callback, stretch, name)

Ajoute un champ texte. Le callback est appelé à chaque frappe avec le texte courant.

ui.add_input("Email", name="email")
ui.add_input("Rechercher...", callback=lambda texte: filtrer(texte))

Pour lire la valeur plus tard :

valeur = ui.get("email").text()

add_dropdown(options, callback, stretch, name)

Ajoute une liste déroulante. Le callback reçoit la valeur sélectionnée à chaque changement.

ui.add_dropdown(["Français", "English", "Español"], name="langue")
ui.add_dropdown(["Option A", "Option B"], callback=lambda val: print(val))

add_checkbox(text, callback, checked, stretch, name)

Ajoute une case à cocher. Le callback reçoit True ou False.

ui.add_checkbox("Mode sombre", callback=lambda etat: toggle_theme(etat))
ui.add_checkbox("Accepter les CGU", checked=False, name="cgu")

Mise en page

add_row(stretches, stretch, align, cross_align)

Crée une ligne — les éléments ajoutés dedans s'alignent horizontalement. Retourne la nouvelle Section enfant.

row = ui.add_row()
row.add_button("Oui", lambda: print("oui"))
row.add_button("Non", lambda: print("non"))

Avec chaînage et .end() pour remonter au parent :

ui.add_row() \
  .add_button("Oui", lambda: print("oui")) \
  .add_button("Non", lambda: print("non")) \
  .end() \
  .add_label("Suite du contenu principal")

add_column(stretches, stretch, align, cross_align)

Crée une colonne — les éléments ajoutés dedans s'empilent verticalement. Fonctionne exactement comme add_row mais dans l'axe vertical.

ui.add_row([1, 2, 1]) \
  .add_column().add_label("Gauche").end() \
  .add_column().add_label("Centre (double)").end() \
  .add_column().add_label("Droite")

end()

Remonte à la Section parente pour continuer le chaînage à un niveau supérieur.

ui.add_column() \
  .add_label("Dans la colonne") \
  .add_button("Bouton", callback) \
  .end() \                          # ← remonte au contenu principal
  .add_label("Hors de la colonne")

clear()

Supprime tous les éléments d'une section. Utile pour reconstruire dynamiquement une zone.

section = ui.add_column(name="zone-dynamique")
# ... plus tard ...
section.clear()
section.add_label("Nouveau contenu")

Positionnement

Espacement fixe : add_spacing(px)

Ajoute un espace fixe entre deux éléments, en pixels. Ne consomme pas de stretch.

ui.add_label("Titre")
ui.add_spacing(20)           # 20px d'espace fixe
ui.add_button("Bouton", cb)

Espace élastique : add_spacer(stretch)

Ajoute un espace vide qui s'étire. Utile pour pousser des éléments vers un bord.

# Bouton collé à droite
ui.add_row() \
  .add_spacer(1) \             # pousse tout vers la droite
  .add_button("OK", cb)

# Bouton centré
ui.add_row() \
  .add_spacer(1) \
  .add_button("Centré", cb) \
  .add_spacer(1)

Proportions : stretches=[...]

Passe une liste de ratios à add_row() ou add_column(). Chaque valeur est consommée dans l'ordre par les éléments ajoutés.

# 3 colonnes : 1/4 - 2/4 - 1/4
ui.add_row([1, 2, 1]) \
  .add_column().add_label("Gauche").end() \
  .add_column().add_label("Centre").end() \
  .add_column().add_label("Droite")

Le paramètre stretch par élément prend la priorité sur la liste si les deux sont fournis.


Alignement : align

Positionne le groupe d'éléments sur l'axe principal de la section.

Valeur Effet sur une colonne Effet sur une ligne
"top" Éléments en haut
"bottom" Éléments en bas
"left" Éléments à gauche
"right" Éléments à droite
"center" Éléments centrés Éléments centrés
ui.add_column(align="center") \
  .add_button("Centré verticalement", cb)

Alignement croisé : cross_align

Positionne les éléments sur l'axe perpendiculaire.

Sur une colonne (axe vertical) → cross_align gère l'horizontal : "left", "right", "center"

Sur une ligne (axe horizontal) → cross_align gère le vertical : "top", "bottom", "center"

# Boutons centrés verticalement ET collés à gauche
ui.add_column(align="center", cross_align="left") \
  .add_button("A", cb) \
  .add_button("B", cb)

Marges : set_margins(top, right, bottom, left)

Définit les marges intérieures d'une section en pixels.

ui.add_column() \
  .set_margins(top=10, left=15, right=15, bottom=10) \
  .add_label("Avec marges")

Espacement global : set_spacing(px)

Définit l'espacement entre tous les éléments d'une section.

ui.sidebar("left") \
  .set_spacing(8) \            # 8px entre chaque élément
  .add_button("A", cb) \
  .add_button("B", cb)

Sidebars

ui.sidebar(side) crée et retourne une Section positionnée sur un des quatre bords de la fenêtre. Elle n'est créée qu'au premier appel (lazy) — pas de coût si non utilisée.

ui.sidebar(side, stretches, align, cross_align, size)
Paramètre Description
side "left", "right", "up", "down"
stretches Liste de ratios pour les éléments
align Alignement sur l'axe principal
cross_align Alignement sur l'axe perpendiculaire
size Largeur (left/right) ou hauteur (up/down) fixe en pixels
# Sidebar gauche avec boutons en haut
ui.sidebar("left", align="top", size=160) \
  .set_margins(top=10, left=8, right=8) \
  .set_spacing(6) \
  .add_label("Navigation") \
  .add_separator() \
  .add_button("Accueil", cb) \
  .add_button("Paramètres", cb)

# Barre du bas centrée horizontalement
ui.sidebar("down", align="center", cross_align="center", size=40) \
  .add_label("Version 1.0.0")

Note : cross_align sur "up" / "down" accepte "top", "bottom", "center". Sur "left" / "right" il accepte "left", "right", "center".


Onglets

add_tabs(tabs, stretch, name)

Crée un widget à onglets. Retourne un dictionnaire {nom_onglet: Section}.

pages = ui.add_tabs(["Accueil", "Paramètres", "À propos"])

pages["Accueil"] \
  .add_label("Bienvenue !") \
  .add_button("Action", cb)

pages["Paramètres"] \
  .add_input("Nom", name="nom") \
  .add_checkbox("Mode sombre")

pages["À propos"] \
  .add_label("Version 1.0.0")

Le paramètre name permet de cibler le widget en QSS via #nom-des-onglets.


Scroll

add_scroll(stretch, horizontal)

Crée une zone scrollable. Retourne la Section intérieure dans laquelle on ajoute du contenu normalement.

Paramètre Défaut Description
horizontal False Active le scroll horizontal si True
scroll = ui.add_scroll()
for i in range(50):
    scroll.add_label(f"Ligne {i}")

Tables

add_table(columns, rows, stretch)

Crée un tableau avec des colonnes nommées. Retourne le QTableWidget pour pouvoir y ajouter des lignes.

table = ui.add_table(["Nom", "Age", "Ville"])

add_table_row(table, values)

Ajoute une ligne de données à un tableau existant.

table = ui.add_table(["Nom", "Age", "Ville"])
ui.add_table_row(table, ["Alice", "30", "Paris"])
ui.add_table_row(table, ["Bob",   "25", "Lyon"])

Références nommées

name= sur les widgets

La plupart des méthodes add_* acceptent un paramètre name. Cela enregistre le widget sous ce nom ET lui assigne un objectName Qt pour le ciblage QSS.

ui.add_input("Email", name="email")
ui.add_button("Supprimer", cb, name="btn-suppr")

section.get(name)

Récupère un widget enregistré par son nom pour lire ou modifier sa valeur dynamiquement.

# Lire la valeur d'un input
valeur = ui.get("email").text()

# Modifier un label
ui.get("titre").setText("Nouveau titre")

# Changer l'état d'une checkbox
ui.get("mode-sombre").setChecked(True)

Styling et thèmes

Fichier QSS : ui.load_style(path)

La méthode recommandée. Charge un fichier .qss (syntaxe CSS) et l'applique globalement.

ui.load_style("style/style.qss")

Dans le fichier QSS, on peut cibler :

  • Par type : QPushButton, QLabel, QLineEdit...
  • Par objectName : #sidebar-left, #email, #btn-suppr
  • Par hiérarchie : QWidget#sidebar-left QPushButton
  • Par état : :hover, :pressed, :focus, :checked, :disabled
/* Tous les boutons */
QPushButton {
    background-color: #3a3a3a;
    border-radius: 6px;
    padding: 5px 12px;
}

/* Un bouton spécifique */
#btn-suppr {
    background-color: #8b0000;
    color: white;
}

/* La sidebar gauche */
QWidget#sidebar-left {
    background-color: #161616;
    border-right: 1px solid #333;
}

Style local : section.set_style(css)

Applique du CSS Qt uniquement sur le widget conteneur d'une section donnée.

ui.sidebar("left") \
  .set_style("background-color: #161616; border-right: 1px solid #333;")

Notifications

ui.notify(text, kind, duration)

Affiche un bandeau coloré flottant en bas de la fenêtre, qui disparaît automatiquement.

kind Couleur
"info" Bleu foncé
"success" Vert
"warning" Orange foncé
"error" Rouge foncé
ui.notify("Fichier sauvegardé", "success")
ui.notify("Champ requis manquant", "warning", duration=4000)
ui.notify("Connexion perdue", "error", duration=0)   # ne disparaît pas

notify s'appelle toujours sur ui, pas sur une section.


Fenêtres secondaires

ui.open_window(title, width, height, padding)

Ouvre une nouvelle fenêtre indépendante. Retourne un UIWrapper complet avec toute la même API.

def ouvrir_parametres():
    win = ui.open_window("Paramètres", width=350, height=250, padding=10)
    win.add_label("Préférences") \
       .add_checkbox("Notifications") \
       .add_button("Fermer", lambda: win.window.close())

ui.add_button("Paramètres", ouvrir_parametres)

Inspector

L'inspector analyse l'arbre de widgets sans rien modifier. Il fonctionne sur n'importe quel QWidget Qt.

from ui.ui_inspector import print_tree, save_tree, generate_qss

print_tree(root)

Affiche l'arborescence complète de l'interface dans le terminal.

print_tree(ui.window)

Exemple de sortie :

QMainWindow
└─ QWidget  [central]
   └─ QWidget  [middle]
      ├─ QWidget  [sidebar-left]
      │  ├─ QLabel  'Navigation'
      │  └─ QPushButton  'Accueil'  [#btn-accueil]
      └─ QWidget  [content]
         └─ QLabel  'Bienvenue !'

save_tree(root, path)

Sauvegarde la même arborescence dans un fichier texte.

save_tree(ui.window, "ui_tree.txt")

generate_qss(root, path)

Génère automatiquement un fichier .qss pré-rempli à partir de l'arbre. Tous les types de widgets trouvés et tous les objectName sont listés avec leurs propriétés commentées — il n'y a plus qu'à décommenter et remplir les valeurs.

generate_qss(ui.window, "style/style.qss")

Le fichier généré ressemble à :

/* ================================================================ */
/* QSS généré automatiquement par ui_inspector                      */
/* ================================================================ */

/* ── Styles globaux par type ── */

QPushButton {
    /* background-color: ;
    color: ;
    border-radius: px; */
}

/* ── Styles spécifiques par nom ── */

#sidebar-left {
    /* background-color: ; */
}

#btn-accueil {
    /* background-color: ; */
    /* color: ; */
}

Raccourcis et bonnes pratiques

Construire l'interface avant run() Tous les add_*, sidebar(), load_style() doivent être appelés avant ui.run().

Utiliser name= dès le départ Même si vous ne lisez pas encore la valeur, nommer les widgets dès la création permet de les cibler en QSS sans toucher au Python.

Générer le QSS avec l'inspector Construire l'interface d'abord, appeler generate_qss(), puis customiser le fichier généré. C'est bien plus rapide que de deviner les sélecteurs.

Ordre de configuration recommandé

ui = UIWrapper(...)      # 1. Créer
ui.load_style(...)       # 2. Style
ui.set_icon(...)         # 3. Icône
ui.set_resizable(...)    # 4. Contraintes
ui.center()              # 5. Position

# 6. Construire l'interface
ui.sidebar("left") ...
ui.add_label(...) ...

# 7. (optionnel) Inspector
generate_qss(ui.window)

ui.run()                 # 8. Lancer

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distributions

No source distribution files available for this release.See tutorial on generating distribution archives.

Built Distributions

If you're not sure about the file name format, learn more about wheel file names.

uiwrapper-0.1.2-cp312-cp312-win_amd64.whl (392.9 kB view details)

Uploaded CPython 3.12Windows x86-64

uiwrapper-0.1.2-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl (1.3 MB view details)

Uploaded CPython 3.12manylinux: glibc 2.17+ x86-64

uiwrapper-0.1.2-cp312-cp312-macosx_10_13_universal2.whl (558.2 kB view details)

Uploaded CPython 3.12macOS 10.13+ universal2 (ARM64, x86-64)

File details

Details for the file uiwrapper-0.1.2-cp312-cp312-win_amd64.whl.

File metadata

  • Download URL: uiwrapper-0.1.2-cp312-cp312-win_amd64.whl
  • Upload date:
  • Size: 392.9 kB
  • Tags: CPython 3.12, Windows x86-64
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.12

File hashes

Hashes for uiwrapper-0.1.2-cp312-cp312-win_amd64.whl
Algorithm Hash digest
SHA256 854aa27dda41305e8db94be0f598b32dfc1432f86f9a909d28d0b2cc6c2b281c
MD5 efc6d07be6be403a0a42a65c56bbf72d
BLAKE2b-256 0a20342ff2f85dcbc5d8ff2544c81efc5afb747b8025c3617d02bf3238dfdfb9

See more details on using hashes here.

File details

Details for the file uiwrapper-0.1.2-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl.

File metadata

File hashes

Hashes for uiwrapper-0.1.2-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl
Algorithm Hash digest
SHA256 e35d7db101c4b616c9db8118f8a8ba28fd71181d495781a7f7fdf66b96834d35
MD5 f9bc5dd7191ca082c919a1b14bf1f4cf
BLAKE2b-256 6a9ffab5be0ba7b5111d9e92794de297d14e60d815a1841fc1fc73f7e663339b

See more details on using hashes here.

File details

Details for the file uiwrapper-0.1.2-cp312-cp312-macosx_10_13_universal2.whl.

File metadata

File hashes

Hashes for uiwrapper-0.1.2-cp312-cp312-macosx_10_13_universal2.whl
Algorithm Hash digest
SHA256 a4276b8b720b4e49e964ad74484f8b4f4a976a8a84c509c5315838b954c40039
MD5 f31620a2a817154d2caed8c3fa97b638
BLAKE2b-256 fd5d2d049162c00197792fc7b7316ceb6b09763c1b99a4558869adaf1b4f46ed

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page