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.1-cp312-cp312-win_amd64.whl (392.9 kB view details)

Uploaded CPython 3.12Windows x86-64

uiwrapper-0.1.1-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.1-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.1-cp312-cp312-win_amd64.whl.

File metadata

  • Download URL: uiwrapper-0.1.1-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.1-cp312-cp312-win_amd64.whl
Algorithm Hash digest
SHA256 f1e4858cbcee4754f26489570f6947361cd9167594c4be883e0d7a89a5c99dbd
MD5 0f63bc080222044c144df807fae0e844
BLAKE2b-256 a96aafde012ff79a873d2a6bc8b039d511b38823363134df58ae131877b464a8

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for uiwrapper-0.1.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl
Algorithm Hash digest
SHA256 86681c4696b49ab3c1aafc92f380450dc48f08d2cc7c9f66eda6e81d83b221ed
MD5 27f23a7e8b1fc3905d936b420844363e
BLAKE2b-256 e134640bd5de227cacfe3c24dd0262b42891175908324fcfd5cd72218c950e26

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for uiwrapper-0.1.1-cp312-cp312-macosx_10_13_universal2.whl
Algorithm Hash digest
SHA256 fa90204bf28789b4197deaaa6846d500f23dede2bd4350cc734b942151b12601
MD5 5f90da956983f19c88875cf50d71d41a
BLAKE2b-256 f300c150ffd0ea494bdd3120d60448d662394841bdecfa3e6b84cc91a60ceb43

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