⇨ MENU ⇨ MODULES ⇨ tkinter ⇨ extension ttk ⇨ Style
Généralités tkinter.ttk.Style ( )
⇨ MENU ⇨ MODULES ⇨ tkinter ⇨ extension ttk ⇨ Style
Généralités tkinter.ttk.Style ( )
Cette page tentera de vous guider pour acquérir rapidement les connaissance pour devenir relativement opérationnel avec la classe tkinter.ttk.Style ( ) pour Python. Elle présente les éléments indispensables sur les concepts de base, la mise en page, et les événements des thèmes, et des styles, dont vous avez besoin pour votre application.
Cependant, avant de ce lancer il convient de ce rappeler que, très peu type de programmes demanderont un changement de thème. L'utilisation des controles standards de tkinter suffiront le plus souvent à satisfaire à l'attende des utilisateurs. Seuls certains logiciels, comme des jeux éducatifs, pourront constituer des exceptions et justifier l'investissement de temps et de ressources nécessaires à l'utilisation des controles tkinter.ttk .
Avant d'entreprendre un nouveau produit conçu avec des controles donc l'aspect est géré par la classe tkinter.ttk.Style ( ) plutot que des attributs standards (tkinter), il faut bien comprendre que cette façon de faire :
- s'adresse à des personnes ayant de bonnes, voire excellentes, notions de design ;
- est plus complexe, mais pas plus compliquée, et donc demande plus de temps ;
- demande un apprentissage plus long pour acquérir de l'expérience ;
Rappel : L'aspect finale d'une application ayant une GUI, interface graphique, dépends essentiellement de l'environnement et des propriétés du système d'explotation sur laquelle s'exécute le programme. Il faut bien garder à l'esprit que le résultat sera très différent sur Linux, Windows ou MacOs.
Changer de thème donne à l'application un look différent en modifiant tous les controles de l'interface, alors que changer de style n'en modifie qu'un groupe de controles associés à ce style. en résumé :
- les styles, qui régentent l'apparence des controles et :
- les thèmes, qui sont des une collection de styles, qui définissent l'apparence des controles du programme.
Les thèmes et les styles rend le script plus élégant et concis. Par exemple, si l'interface graphique possède un grand nombre de boutons cliquables, il n'est pas utilise de recopier les détails exacts des attributs gérant leur apparence pour chacun d'eux . Au lieu de cela, vous leur attribuez un style. De plus, la gestion des styles peut aussi être placés à un emplacement précis dans le programme, voir dans un fichier externe qui pourra être importé par le script. Et comme différent type de controles peuvent avoir des aspects identiques, cela favorise l'homogénéité et enrichi la réutilisation.
Avec l'importation de tkinter.ttk, l'application dispose de thèmes proposés par défaut. Les thèmes sont identifiés par un nom. La méthode tkinter.ttk.Style ( ).theme_names ( ) retourne la liste des thèmes, et donc de leur noms, actuellement disponibles.
import tkinter , tkinter.ttk
TKI_Principal = tkinter.Tk ( )
TKV_Themes = tkinter.StringVar ( )
for ktheme in tkinter.ttk.Style ( ).theme_names ( ) : TKV_Themes.set ( f"{ TKV_Themes.get ( ) }{ ktheme }\n" )
tkinter.ttk.Label ( TKI_Principal , textvariable = TKV_Themes ).pack ( )
tkinter.ttk.Button ( TKI_Principal , text = "Quitter" , command = TKI_Principal.destroy ).pack ( )
TKI_Principal.mainloop ( )
La méthode tkinter.ttk.Style ( ).theme_use ( ) , employée sans argument, retourne le nom du thème actuellement utilisé.
import tkinter , tkinter.ttk
TKI_Principal = tkinter.Tk ( )
TKV_Themes = tkinter.StringVar ( )
tkinter.ttk.Label ( TKI_Principal , text = f"\n Thème actuel : { tkinter.ttk.Style ( ).theme_use ( ) }. \n" ).pack ( )
tkinter.ttk.Button ( TKI_Principal , text = "Quitter" , command = TKI_Principal.destroy ).pack ( )
TKI_Principal.mainloop ( )
La méthode tkinter.ttk.Style ( ).theme_use ( theme ), où theme est un nom de thème existant, modifie le thème d'apparence de l'interface graphique. L'interface graphique ne peut utiliser qu'un seul thème à la fois.
import tkinter , tkinter.ttk
FNC_Theme = lambda event : tkinter.ttk.Style ( ).theme_use ( BOX_Choix.get ( ) )
TKI_Principal = tkinter.Tk ( )
BOX_Choix = tkinter.ttk.Combobox ( TKI_Principal , values = tkinter.ttk.Style ( ).theme_names ( ) )
BOX_Choix.bind ( "<<ComboboxSelected>>" , FNC_Theme )
BOX_Choix.set ( tkinter.ttk.Style ( ).theme_use ( ) )
tkinter.ttk.Label ( TKI_Principal , text = "\n Test de changement \n" , relief = "solid" ).pack ( padx = 5 , pady = 5 )
tkinter.ttk.Checkbutton ( TKI_Principal , text = "Coche" ).pack ( )
tkinter.ttk.Radiobutton ( TKI_Principal , text = "Radio" ).pack ( )
tkinter.ttk.Scale ( TKI_Principal , orient = "horizontal" ).pack ( padx = 5 , pady = 5 )
tkinter.ttk.Scrollbar ( TKI_Principal , orient = "horizontal" ).pack ( fill = "both" , padx = 5 , pady = 5 )
BOX_Choix.pack ( padx = 5 , pady = 5 )
tkinter.Button ( TKI_Principal , text = "Quitter" , command = TKI_Principal.destroy ).pack ( )
FNC_Theme ( None )
TKI_Principal.mainloop ( )
La méthode tkinter.ttk.Style ( ).configure ( style ), où style est un nom de style existant, retourne un dict ( ) avec toutes les valeurs des options du style.
import tkinter , tkinter.ttk
def FNC_Style ( event ) :
tkinter.ttk.Style ( ).theme_use ( BOX_Theme.get ( ) )
BOX_Options.delete ( 0 , "end" )
koptions = tkinter.ttk.Style ( ).configure ( BOX_Style.get ( ) )
if koptions != None :
for koption , kvaleur in koptions.items ( ) :
BOX_Options.insert ( "end" , f"{ koption } : { kvaleur }" )
TKI_Principal = tkinter.Tk ( )
BUT_Quitter = tkinter.Button ( TKI_Principal , text = "Quitter" , command = TKI_Principal.destroy )
BOX_Theme = tkinter.ttk.Combobox ( TKI_Principal , values = tkinter.ttk.Style ( ).theme_names ( ) )
BOX_Style = tkinter.ttk.Combobox ( TKI_Principal , values = ( "." , "TButton" , "TCheckbutton" , "TCombobox" , "TEntry" , "TFrame" , "TLabel" , "TLabelFrame" , "TMenubutton" , "TNotebook" , "TPanedWindow" , "TProgressbar" , "TRadiobutton" , "TScale" , "TScrollbar" , "TSeparator" , "TSizegrip" , "TSpinbox" , "Treeview" ) )
BOX_Options = tkinter.Listbox ( TKI_Principal )
BOX_Theme.bind ( "<<ComboboxSelected>>" , FNC_Style )
BOX_Style.bind ( "<<ComboboxSelected>>" , FNC_Style )
BOX_Theme.set ( tkinter.ttk.Style ( ).theme_use ( ) )
BOX_Style.set ( "." )
tkinter.ttk.Label ( TKI_Principal , text = "\n Themes et Styles \n" , relief = "solid" ).grid ( row = 0 , column = 0 )
BOX_Options.grid ( row = 0 , column = 1 , rowspan = 4 )
tkinter.ttk.Checkbutton ( TKI_Principal , text = "Coche" ).grid ( row = 0 , column = 2 )
BOX_Theme.grid ( row = 1 , column = 0 )
tkinter.ttk.Radiobutton ( TKI_Principal , text = "Radio" ).grid ( row = 1 , column = 2 )
BOX_Style.grid ( row = 2 , column = 0 )
tkinter.ttk.Scale ( TKI_Principal , orient = "horizontal" ).grid ( row = 2 , column = 2 )
BUT_Quitter.grid ( row = 3 , column = 0 )
tkinter.ttk.Scrollbar ( TKI_Principal , orient = "horizontal" ).grid ( row = 3 , column = 2 , sticky = "nesw" )
FNC_Style ( None )
TKI_Principal.mainloop ( )
Un controle est composé de plusieurs parties appelées : éléments. Par exemple : un bouton cliquable est composé, de l'extérieur vers l'intérieur : d'une bordure ; d'un indicateur de prise de focus , d'une zone de fond vide , d'un texte. il est donc composés de quatre éléments. Note : il ne s'agit que d'un modèle de bouton, on peut contruire un bouton cliquable en agençant d'autres éléments de façon différente. On peut donc présenter la structure des éléments du bouton cliquable de l'exemple comme suit :
- le bouton est limité par une bordure : "border" ;
- qui borde un indicateur de focus : "focus" ;
- qui entoure un zone de fond vide : "background" ;
- qui contient le texte du bouton : "label".
La méthode tkinter.ttk.Style ( ).element_names ( ) retourne la liste des éléments qui peuvent être utilisés pour construit un controle dans un style. Ces éléments sont : "" ; "arrow" ; "background" ; "border" ; "Checkbutton.indicator" ; "client" ; "downarrow" ; "field" ; "fill" ; "focus" ; "hsash" ; "hseparator" ; "image" ; "indicator" ; "label" ; "leftarrow" ; "Menubutton.indicator" ; "padding" ; "pbar" ; "Radiobutton.indicator" ; "rightarrow" ; "separator" ; "sizegrip" ; "slider" ; "tab" ; "text" ; "textarea" ; "thumb" ; "treearea" ; "Treeheading.cell" ; "Treeitem.indicator" ; "Treeitem.row" ; "trough" ; "uparrow" ; "vsash" ; "vseparator".
Chaque élément a plusieurs attributs de formatage. Par exemple, un élément texte "label" a : une fonte "font" ; un alignement "justify" ; une couleur d'encre "foreground" ; une couleur de fond "background" ; un ancrage "anchor" ; ... Ces attributs peuvent recevoir une valeur différentes pour personnaliser l'élément texte du controle et le différencier d'un style à l'autre.
La méthode tkinter.ttk.Style ( ).element_options ( element ), où element est un nom de élément valide, la liste des attribut possible pour element.
import tkinter , tkinter.ttk
def FNC_Attribut ( event ) :
kindex = BOX_Elements.curselection ( ) [ 0 ]
kelement = ( BOX_Elements.get ( kindex ) )
TKV_Attributs.set ( tkinter.ttk.Style ( ).element_options ( kelement ) )
TKI_Principal = tkinter.Tk ( )
TKV_Elements = tkinter.StringVar ( )
TKV_Attributs = tkinter.StringVar ( )
BUT_Quitter = tkinter.Button ( TKI_Principal , text = "Quitter" , command = TKI_Principal.destroy )
BOX_Elements = tkinter.Listbox ( TKI_Principal , listvariable = TKV_Elements )
BOX_Attributs = tkinter.Listbox ( TKI_Principal , listvariable = TKV_Attributs )
TKV_Elements.set ( tkinter.ttk.Style ( ).element_names ( ) )
BOX_Elements.bind ( "<ButtonRelease-1>" , FNC_Attribut )
tkinter.Label ( TKI_Principal , text = "Eléments" ).grid ( row = 0 , column = 0 )
BOX_Elements.grid ( row = 1 , column = 0 )
tkinter.Label ( TKI_Principal , text = "Attributs" ).grid ( row = 0 , column = 1 )
BOX_Attributs.grid ( row = 1 , column = 1 )
BUT_Quitter.grid ( row = 2 , column = 1 )
BOX_Elements.select_set ( 0 )
FNC_Attribut ( None )
TKI_Principal.mainloop ( )
La méthode tkinter.ttk.Style ( ).layout ( style ), où style est un nom de style existant, retourne la liste des éléments, leur disposition, ou emboitement, et leurs caractéristiques.
import tkinter , tkinter.ttk
def FNC_Style ( event ) :
TXT_Elements.delete ( "1.0" , "end" )
tkinter.ttk.Style ( ).theme_use ( BOX_Theme.get ( ) )
try :
kelements = str ( tkinter.ttk.Style ( ).layout ( BOX_Style.get ( ) ) )
kdisposition = kelements.replace ( "[(" , "\n[(" )
TXT_Elements.insert ( "1.0" , kdisposition )
except : pass
TKI_Principal = tkinter.Tk ( )
BUT_Quitter = tkinter.Button ( TKI_Principal , text = "Quitter" , command = TKI_Principal.destroy )
BOX_Theme = tkinter.ttk.Combobox ( TKI_Principal , values = tkinter.ttk.Style ( ).theme_names ( ) )
BOX_Style = tkinter.ttk.Combobox ( TKI_Principal , values = ( "." , "TButton" , "TCheckbutton" , "TCombobox" , "TEntry" , "TFrame" , "TLabel" , "TLabelFrame" , "TMenubutton" , "TNotebook" , "TPanedWindow" , "TProgressbar" , "TRadiobutton" , "TScale" , "TScrollbar" , "TSeparator" , "TSizegrip" , "TSpinbox" , "Treeview" ) )
TXT_Elements = tkinter.Text ( TKI_Principal , wrap = "none" , height = 8 )
BOX_Theme.bind ( "<<ComboboxSelected>>" , FNC_Style )
BOX_Style.bind ( "<<ComboboxSelected>>" , FNC_Style )
BOX_Theme.set ( tkinter.ttk.Style ( ).theme_use ( ) )
BOX_Style.set ( "TButton" )
tkinter.ttk.Label ( TKI_Principal , text = "\n Eléments du styles : \n" ).grid ( row = 0 , column = 0 )
BOX_Theme.grid ( row = 0 , column = 1 )
BOX_Style.grid ( row = 0 , column = 2 )
BUT_Quitter.grid ( row = 0 , column = 3 )
TXT_Elements.grid ( row = 1 , column = 0 , columnspan = 4 , sticky = "nesw" )
FNC_Style ( None )
TKI_Principal.mainloop ( )
Donc, les styles sont constitués d'éléments avec diverses attributs. Les éléments sont regroupés dans une mise en page. On peut modifier les attributs des styles pour que tous les controles utilisant le style apparaissent différemment de leur aspect de base. Tous les controles associés à un style prennent l'aspect définie par le style. Plusieurs styles sont assemblés pour constituer un thème complet. Changer de thème modifie l'apparence entière de l'interface graphique, à condition que le nouveau thème ait des styles de même noms que le thème précédent.
Alors, pourquoi les styles et les thèmes sont si délicat d'emploi dans la pratique ?
D'abord ...
A l'exception de quelques cas particuliers, on ne peut modifier que les attributs d'un style, pas les attributs des éléments. L'identification des éléments utilisés dans le style doit se faire en examinant sa disposition et en identifiant les attributs disponibles pour chaque élément. Mais pour apporter des modifications à un style, il faut configurer un attribut pour le style sans spécifier un élément individuel. Que se passe-t-il ?
Dans l'exemple du bouton, nous avions un élément "Button.label", qui avait un attribut "font" pouvant être configuré. Lorsque cet élément "Button.label" est dessiné, il regarde son attribut "font" définie sur le style pour déterminer dans quelle police il sera affiché.
Parce que lorsqu'un style inclut un élément, en tant que partie de celui-ci, cet élément ne mémorise rien de spécifique à lui même. Un élément ne stocke lui-même aucune valeur de ses attributs. S'il a besoin de restituer les valeurs de ses attributs, il interroge son style conteneur. Les éléments individuels sont donc des composants de très faible poids.
Comme un style ne peut stoker qu'une seule valeur par attribut, si deux éléments utilisent le même attribut, par exemple foreground, ils recevront la même valeur pour cette attribut. Tous les éléments d'un même type apparaitront avec le même visuel.
Certains styles offrent des possibilités additionnelles permettant de spécifier l'élément affecté par l'attribut. Par exemple, le style "TCheckbutton" fournit un attribut background comme couleur de fond du controle, mais aussi un attribut indicatorbackground pour celle de la case quand elle est cochée.
Ensuite ...
Tous les attributs n'ont pas obligatoirement d'effet. Par exemple, bien quand général, l'attribut background du style "TButton" permet de de modifier la couleur de fond des boutons cliquables, son utilisation, bien qu'autorisée, dans le thème "aqua" proposé par tkinter.ttk pour MacOs sera ignorée. Ces exceptions ne sont facile à découvrir, ce qui rend l'expérimentation frustrante.
Il faut aussi notez qu'un nom de style ou attributs non valide ne lèvera pas d'exception. L'emploi des méthodes tkinter.ttk.Style ( ).configure ( ) et tkinter.ttk.Style ( ).lookup ( ), peut ce faire en donnant des noms de styles ou d'attributs entièrement arbitraire. Donc, configurer un attribut flechedevant ne fera peut-être rien, mais ce n'est pas une erreur pour autant.
C'est l'un des inconvénients d'avoir un système très léger et dynamique. On peut créer de nouveaux styles en fournissant un nom quelconque lors de la configuration des attributs, sans créer réellement un objet de style. Cela pourra engendrer de nombreuses sources d'erreurs. Il est aussi impossible de savoir quels styles sont effectivement créer dans un thème. La mise au point d'un style n'est qu'une interface pour la reconfiguration de ses éléments, et que ses éléments peuvent changer à tout moment. Il faut donc aussi penser aux attributs et aux élément qui seraient absent du style au moment de sa configuration.
Enfin ...
Les éléments, leurs noms, leurs attributs peuvent être différents dans chaque thème. Et que les thème par défaut dépendent du système d'exploitation utilisé (Linux, Windows, macOS, ... ) mais aussi parfois de sa version.
Donc, définir un nouveau type de controle, ou une variante d'un controle existant, doit se faire différemment, et séparément, pour chaque système d'exploitation sur lesquels l'application est destinée pour obtenir un développement multiplateformes. Sans oublier de considérer que les éléments et les options disponibles peuvent différer pour chaque plateforme, il faut donc une approche de personnalisation assez différente pour chaqu'une d'elles.
Il est rare que les constituant d'un thème soit documentés. Un accès immédiat au thème envisager pour chaque plate-forme devient vite une nécessité. La personnalisation des boutons cliquables doit reconfigurer le style "TButton" présent dans le thème. Mais ce style est mis en œuvre en utilisant un thème différent sur chaque plate-forme, même s'il porte des noms identiques. La disposition d'un style dans chaque thème, utilise différents éléments disposés différemment. Essayer de trouver les attributs annoncées disponibles pour chaque élément, montre qu'ils sont aussi différentes. De plus, si un attribut s'avère disponible, son effet peut être ignoré.
Avant d'entreprendre un nouveau produit conçue avec des controles donc l'aspect est géré par un style, il faut bien comprendre que cette façon de faire s'adresse à des personnes ayant de bonnes, voire excellentes, notions de design ; et est plus complexe, mais pas plus compliquée, et donc demande plus de temps et ressources.
Votre aide est précieuse pour améliorer ce site, alors n'hésitez pas à faire part de