Outils pour utilisateurs

Outils du site


issue194:python

Last month, we looked at playing some tricks on the ttk TNotebook widget with the style manipulation Python module that I wrote called “mystyles_dark.py”. I also promised that I would focus more on that module to provide some insight on how it all works. Since then, I’ve modified the theme file so it isn’t quite as dark, and to do some other things that the original couldn’t. The new file is called “mystyles_notsodark.py”, and that’s what we’ll concentrate on in this month’s article. The files will be available in my repository, which I will share with you at the end of the article.

Le mois dernier, nous avons essayé de jouer quelques tours sur le widget TNotebook de ttk avec le module Python de manipulation de style que j'ai écrit et qui s'appelle « mystyles_dark.py ». J'ai également promis que je me concentrerais davantage sur ce module afin de donner un aperçu de son fonctionnement.

Depuis, j'ai modifié le fichier du thème pour qu'il ne soit pas aussi sombre, et pour qu'il puisse faire d'autres choses que l'original ne pouvait pas faire. Le nouveau fichier s'appelle « mystyles_notsodark.py », et c'est sur cela que nous allons nous concentrer dans l'article de ce mois-ci. Les fichiers seront disponibles dans mon dépôt, que je partagerai avec vous à la fin de l'article.

The original code was the starting point of my notsodark Tcl theme. I use the styling module as my testbed to make sure that I could make things work using Python, since my knowledge of Tcl/Tk was and still is limited. I looked at almost every Tcl theme I could, including the source for the four Linux “default” themes alt, clam, classic and of course default. I have to admit, it took me a while to figure out how to convert much of the Tcl code into Python. I had various copies of my beginning Tcl books open at the same time as I was trying to code the Python file and I had many false starts, but I eventually figured it all out. Eventually, I got the color schemes all worked out to something that I liked. That’s enough history, now let’s get started.

Le code original est le point de départ de mon thème Tcl notsodark. J'ai utilisé le module de style comme banc d'essai pour m'assurer que je pouvais faire fonctionner les choses avec Python, puisque ma connaissance de Tcl/Tk était et est toujours limitée. J'ai examiné presque tous les thèmes Tcl possibles, y compris les sources des quatre thèmes Linux « par défaut » alt, clam, classic et, bien sûr, default. Je dois admettre qu'il m'a fallu un certain temps pour comprendre comment convertir une grande partie du code Tcl en Python. J'avais plusieurs copies de mes livres de Tcl pour débutants ouverts en même temps que j'essayais de coder le fichier Python et j'ai eu de nombreux faux départs, mais j'ai fini par tout comprendre. Finalement, j'ai réussi à mettre au point un schéma de couleurs qui me plaisait.

Assez d'histoire, maintenant commençons.

The first thing we’ll look at is the styling module, “mystyles_notsodark.py”. The imports section is where I always start when examining a python module, so that’s where we’ll begin today. import sys import shared import tkinter as tk import os.path Since we are making a “standalone” module, we need to import sys and tkinter. The use of os.path is needed since we are going to make the module operating system agnostic (able to run on Windows, Linux, and Mac), and we want to be able to get to the Assets folder no matter where the user has installed our module; we can use the os.path.join method to concatenate the correct directory separator (“/” or “\”) in the correct places. The other thing we need to import is an empty file called shared.py. We normally use this to enable various modules of a program to communicate between each other. However, there is a secondary benefit of this, which will become clear in a little bit.

La première chose que nous allons examiner est le module de style, « mystyles_notsodark.py ». Je commence toujours par la section des importations lorsque j'examine un module python, et c'est donc par là que nous commencerons aujourd'hui.

import sys

import shared

import tkinter as tk

import os.path

Puisque nous créons un module « autonome », nous devons importer sys et tkinter. L'utilisation de os.path est nécessaire car nous allons rendre le module agnostique au niveau du système d'exploitation (capable de fonctionner sous Windows, Linux et Mac), et nous voulons pouvoir accéder au dossier Assets quel que soit l'endroit où l'utilisateur a installé notre module. Nous pouvons utiliser la méthode os.path.join pour concaténer le séparateur de répertoire correct (« / » ou « \ ») aux endroits corrects. L'autre chose que nous devons importer est un fichier vide appelé shared.py. Nous l'utilisons normalement pour permettre aux différents modules d'un programme de communiquer entre eux. Cependant, il y a un avantage secondaire à cela, qui deviendra clair dans un petit moment.

We put the next three lines just after the import section so that the values are, by scope, implicity global. This means that they are available to any functions with the module as long as they aren’t changed within any of the functions. We have to be careful of this (see below). We can use the location variable to provide the proper base path when we call the os.path.join statements later on.

Nous plaçons les trois lignes suivantes juste après la section import afin que les valeurs soient implicitement globales par définition. Cela signifie qu'elles sont disponibles pour toutes les fonctions du module tant qu'elles ne sont pas modifiées dans l'une de ces fonctions. Nous devons faire attention à cela (voir ci-dessous).

Nous pouvons utiliser la variable location pour fournir le chemin de base approprié lorsque nous appelons les instructions os.path.join plus tard.

Next, we need to do some definitions of color variables that we will need in our various functions. I’ll show only a few of the definitions, but you can look into the actual module. _bgcolor stands for background color, _fgcolor is the foreground color. Now that we have all of our global definitions made, we can start with our first function (top right). The create_styles function takes just one parameter, an instance of ttk.Style(). Since I like to save as many keystrokes as I can, I named that instance sty. The first configure statement creates a set of color definitions that are duplicated from the global definitions. These, however, are supposed to be used for the root style of the theme, which sets the color sets for every ttk widget used in the Toplevel form. It doesn’t seem to actually work in Python like this and the actual colors that can be used are those from the global definition.

Ensuite, nous devons définir les variables de couleur dont nous aurons besoin dans nos différentes fonctions. Je ne montrerai que quelques-unes des définitions, mais vous pouvez consulter le module lui-même. _bgcolor signifie couleur d'arrière-plan, _fgcolor est la couleur d'avant-plan.

Maintenant que toutes nos définitions globales sont faites, nous pouvons commencer avec notre première fonction (en haut à droite).

La fonction create_styles ne prend qu'un seul paramètre, une instance de ttk.Style(). Comme j'aime économiser autant de frappes que possible, j'ai nommé cette instance sty.

La première instruction configure crée un ensemble de définitions de couleurs qui sont dupliquées à partir des définitions globales. Celles-ci sont cependant censées être utilisées pour le style racine du thème, qui définit les jeux de couleurs pour chaque widget ttk utilisé dans le formulaire Toplevel. Cela ne semble pas fonctionner de cette manière en Python et les couleurs qui peuvent être utilisées sont celles de la définition globale.

The next thing is to declare a map for the root style that controls how the widget colors will react to the various states like disabled, active, in focus, not in focus, and so on. Each item must be a list of tuples containing the state followed by the color, even if there is only one state that you are defining (bottom right). Now we can start defining the styles for each widget (middle). I’ll show you only a few choice definitions to give you an idea how it’s done. Here’s the style for the Tbutton.

La prochaine étape consiste à déclarer une carte pour le style racine qui contrôle la façon dont les couleurs des widgets réagiront aux différents états tels que désactivé, actif, en focus, non en focus, etc. Chaque élément doit être une liste de tuples contenant l'état suivi de la couleur, même si vous ne définissez qu'un seul état (en bas à droite).

Nous pouvons maintenant commencer à définir les styles pour chaque widget (au milieu). Je ne vous montrerai que quelques définitions de choix pour vous donner une idée de la façon de procéder. Voici le style du Tbutton (bouton T).

As before, there can be a section for the map of the state to color, and then a section for the “normal” look. If you want to create a style for all the widgets of a particular class, as in the above snippet, you must use the default style name. That almost always begins with a “T”. When we want to set the attributes that we can’t normally set, we need to use the style.configure method. This allows us to set things like background and foreground colors, the padding (a list containing up to four integers for left, top, right and bottom in that order), font and so on. The TButton also has a special style built in called Toolbutton. This, as well, can be overridden by using the same configure and map settings (top right).

Comme précédemment, il peut y avoir une section pour la carte de l'état à colorier, puis une section pour l'aspect « normal ». Si vous souhaitez créer un style pour tous les widgets d'une classe particulière, comme dans l'extrait ci-dessus, vous devez utiliser le nom du style par défaut. Ce nom commence presque toujours par un « T ».

Lorsque nous voulons définir des attributs que nous ne pouvons pas définir normalement, nous devons utiliser la méthode style.configure. Celle-ci nous permet de définir des éléments tels que les couleurs d'arrière-plan et d'avant-plan, le remplissage (une liste contenant jusqu'à quatre entiers pour la gauche, le haut, la droite et le bas dans cet ordre), la police de caractères, etc.

Le TButton possède également un style spécial appelé Toolbutton. Ce style peut également être remplacé en utilisant les mêmes paramètres de configuration et de carte (en haut à droite).

As always, when using images, we have to keep a “temporary” copy of the image object, so Python’s garbage collection doesn’t happily delete it. Now you can see how we use the os.path.join function to define the location of the image we want and the need to use the shared.py file. Next, we need to create a custom element that holds the information on which image is used for which state. This, of course, will change for different widgets and for various element parts. You can create images that will be used to control the shape of the widget and so on (next page, top right). Finally, we have to define the layout. This is the REALLY difficult part. Typically, a widget consists of one or more elements. For the TCheckbutton, there is a border, a padding, a focus and a label. This varies by widget class (next page, bottom right).

Comme toujours, lorsque nous utilisons des images, nous devons conserver une copie « temporaire » de l'objet image, afin que le ramasse-miettes de Python ne l'efface pas par hasard. Vous pouvez maintenant voir comment nous utilisons la fonction os.path.join pour définir l'emplacement de l'image que nous voulons et la nécessité d'utiliser le fichier shared.py.

Ensuite, nous devons créer un élément personnalisé qui contient les informations sur l'image utilisée pour chaque état. Bien entendu, ces informations changeront en fonction des différents widgets et des différentes parties de l'élément. Vous pouvez créer des images qui seront utilisées pour contrôler la forme du widget et ainsi de suite (page suivante, en haut à droite).

Enfin, nous devons définir la mise en page. C'est la partie VRAIMENT difficile. En général, un widget se compose d'un ou plusieurs éléments. Pour le bouton TCheckbutton, il y a une bordure, un padding (remplissage), un focus et une étiquette. C'est variable suivant la classe du widget (page suivante, en bas à droite)

Finally, we can provide the map for the colors for each state (top left). The styling module also provides a custom TRadiobutton definition. I won’t go through all the various ttk widgets that the styling module handles. I tried to deal with every standard ttk widget available. In the process of creating the actual Tcl theme, I added a function that looked important, but I didn’t really know what it did. It didn’t cause anything to throw any errors, so I just left it in. Eventually, I was trying to clean out some of the unneeded code and I came back to the function that I didn’t know what it did. It wasn’t in all the themes that I looked at in my learning process so I decided to look up what it was for. Here is the code (top right).

Enfin, nous pouvons fournir la carte des couleurs pour chaque état (en haut à gauche).

Le module de style fournit également une définition personnalisée du bouton TRadiobutton.

Je ne vais pas passer en revue tous les widgets ttk gérés par le module de style. J'ai essayé de traiter tous les widgets ttk standard disponibles.

Lors de la création du thème Tcl, j'ai ajouté une fonction qui semblait importante, mais je ne savais pas vraiment ce qu'elle faisait. Elle ne provoquait aucune erreur, donc je l'ai laissée. Finalement, j'ai essayé de nettoyer le code inutile et je suis revenu à la fonction dont je ne savais pas ce qu'elle faisait. Parce qu'elle n'était pas dans tous les thèmes que j'ai regardés dans mon processus d'apprentissage, j'ai décidé de chercher à quoi elle servait. Voici le code (en haut à droite).

It turns out that the tk_setPalette function was created to allow for the normally non-themeable Tk widgets to get a pseudo theme applied by letting the tk_setPalette function override the normal database for the Tk widgets. We’ll see more about this when we get into the demo program code, which we’ll do now. Below is what the PAGE designer version of the demo program looks like. You can see that I’ve created the program to use two Labelframes, one for some “generic” Tk widgets and one for the ttk versions of them (where available). Now we’ll look at the code for the demo program. In our demo program, we will skip all the normal imports and jump right into the startup function (bottom right).

Il s'avère que la fonction tk_setPalette a été créée pour permettre aux widgets Tk normalement non-thématisables d'avoir un pseudo-thème appliqué en laissant la fonction tk_setPalette outrepasser la base de données normale pour les widgets Tk. Nous en verrons plus lorsque nous entrerons dans le code du programme de démonstration, ce que nous allons faire maintenant.

Voici à quoi ressemble la version sur PAGE designer du programme de démonstration.

Vous pouvez voir que j'ai créé le programme pour utiliser deux Labelframes, l'un pour certains widgets Tk « génériques » et l'autre pour les versions ttk de ces widgets (lorsqu'elles sont disponibles). Nous allons maintenant examiner le code du programme de démonstration.

Dans notre programme de démonstration, nous allons sauter toutes les importations normales et passer directement à la fonction de démarrage (en bas à droite).

You can see, we define our sty instance of the ttk.Style object, then we call the create_styles function of the styling module. Unfortunately, the ttk.TLabels don’t normally like to be changed via a style, so we use the function fix_Tlabels to set the proper foreground and background colors. Then I put some data into the Tk.Listbox and Tk.Textbox and finally start the TProgressbar which was set to Indeterminate mode in PAGE. Here is the fix_TLabels function. I get the background color from the styling module, then create a list of all the TLabel aliases. Then I simply walk through the list, applying the background color (next page, top right).

Comme vous pouvez le voir, nous définissons notre instance sty de l'objet ttk.Style, puis nous appelons la fonction create_styles du module de stylisme. Malheureusement, les ttk.TLabels n'aiment pas être modifiés par un style ; aussi, nous utilisons la fonction fix_Tlabels pour définir les couleurs d'avant-plan et d'arrière-plan appropriées. Ensuite, je mets des données dans les Tk.Listbox et Tk.Textbox et, enfin, je démarre la TProgressbar qui a été mise en mode Indeterminate (Indéterminé) dans PAGE.

Voici la fonction fix_TLabels. Je récupère la couleur d'arrière-plan dans le module de style, puis je crée une liste de tous les alias de TLabel. Ensuite, je parcours simplement la liste, en appliquant la couleur de fond (page suivante, en haut à droite).

If you look back at the image of the program in the PAGE designer, you will notice two checkboxes near the top of the form near the left side. One is labeled “Show the surprise” and the other “Disable Widgets”. We’ll deal with the “Disable Widgets” callback first (bottom right). Again, I’m going to show only a portion of the widget list. Just like I did in the fix_Tlabels function, I created a list of the aliases of the widgets that I want to be able to control the disabled and normal states. This way, I can demonstrate the way the widgets respond in the different states. The actual list contains both the Tk and ttk widgets that respond to being disabled. I use variable che56, which PAGE assigned for me to find out if the checkbox is checked or not. Based on that, I walk through the widget list and set each widget to the proper disabled or normal state.

Si vous regardez l'image du programme dans le concepteur de pages, vous remarquerez deux cases à cocher en haut du formulaire, près du côté gauche. L'une est intitulée « Afficher la surprise » et l'autre « Désactiver les widgets ». Nous allons d'abord nous occuper de la fonction de rappel « Désactiver les widgets » (en bas à droite).

A nouveau, je ne vais afficher qu'une partie de la liste des widgets. Comme je l'ai fait dans la fonction fix_Tlabels, j'ai créé une liste des alias des widgets dont je veux pouvoir contrôler les états normal et désactivé. De cette façon, je peux démontrer la façon dont les widgets réagissent dans les différents états. La liste actuelle contient à la fois les widgets Tk et ttk qui réagissent quand ils sont désactivés. J'utilise la variable che56, qui est assignée par PAGE pour savoir si la case à cocher est cochée ou non. En fonction de cela, je parcours la liste des widgets et je règle chaque widget dans l'état, désactivé ou normal.

Below is the program running. Now you can see the styling module in “action”. The TCheckbuttons and the TRadiobuttons are using the custom graphics, and the other ttk widgets now have the common style. I set the TCombobox, the TEntry widget, and the TSpinbox to have a complimentary background color that isn’t the standard bright white. Now we can look at the “Show The Surprise” checkbutton callback. The idea here is to call the tk_setPalette function to show the ability to use the style on the Tk widgets (next page, top right). To be able to set the palette back to the “normal” Tk colors, I had to duplicate the set_palette function and then I set the colors back to the standard colors.

Ci-dessous, voici le programme en cours d'exécution.

Vous pouvez maintenant voir le module de style en action. Les boutons TCheckbuttons et TRadiobuttons utilisent les graphiques personnalisés et les autres widgets ttk ont maintenant le style commun. J'ai paramétré le TCombobox, le widget TEntry et le TSpinbox pour qu'ils aient une couleur d'arrière-plan complémentaire qui ne soit pas le blanc éclatant standard.

Nous pouvons maintenant examiner le rappel du bouton « Afficher la surprise ». L'idée ici est d'appeler la fonction tk_setPalette pour montrer la possibilité d'utiliser le style sur les widgets Tk (page suivante, en haut à droite).

Pour pouvoir remettre la palette aux couleurs « normales » de Tk, j'ai dû dupliquer la fonction set_palette, puis remettre les couleurs aux couleurs standard.

Below is what it looks like when we have the “Show The Surprise” checkbutton and the “Disable Widgets” checkbutton selected at the same time. All the widgets now are not only themed, but disabled, and you can see that it’s pretty obvious that the widgets are disabled. Even if the Radiobutton or Checkbuttons are selected, you can still tell those that are selected. One additional feature that the set_Palette function provides is to set the color for the menubar as well. All the files for this project are located in my repository at https://github.com/gregwa1953/FCM194 . Until next time, as always; stay safe, healthy, positive and creative!

Voici ce qui se passe lorsque le bouton « Show The Surprise » (Afficher la surprise) et le bouton « Disable Wedgets » (Désactiver les widgets) sont cochés en même temps.

Tous les widgets sont maintenant non seulement thématisés, mais aussi désactivés ; vous pouvez voir qu'il est assez évident que les widgets sont désactivés. Même si le bouton radio ou les boutons de contrôle sont sélectionnés, vous pouvez toujours reconnaître ceux qui sont sélectionnés.

La fonction set_Palette permet également de définir la couleur de la barre de menus.

Tous les fichiers de ce projet se trouvent dans mon dépôt à l'adresse https://github.com/gregwa1953/FCM194.

Jusqu'à la prochaine fois, comme toujours, restez en sécurité, en bonne santé, positifs et créatifs !

Traduction des lignes noires de l'encadré p 19

It took me a while to figure out how to get the whole custom image thing to work. First, we need to define the images we want to use.

Ça m'a pris du temps pour comprendre comment faire fonctionner toute la personnalisation d'une image. D'abord, nous devons définir les images que nous voulons utiliser.

Traduction de la ligne noire de l'encadré p 20

Then we can handle the basic widget configuration of colors and so on.

Ensuite, nous pouvons gérer la configuration des couleurs du widget de base et ainsi de suite.

issue194/python.txt · Dernière modification : 2023/07/03 14:42 de auntiee