Outils pour utilisateurs

Outils du site


issue193:python

Welcome back my friends. I hope that May finds you all healthy, wealthy and wise. Or at least healthy. This month, I’m going to do another PAGE article, but what I present will be directly relatable to straight Python/Tkinter programming, so I think that it will be a good article for you all. Anyway, let’s get started. I’ll start off with a screenshot (below) of the program as it looks like in the PAGE designer. It’s really nothing but the Toplevel form, a TButton, a TLabelframe holding 12 TRadiobuttons and a TNotebook widget. I’ve gone ahead and edited the TNotebook to have 4 tabs and set a fairly long label on each. And each of the tabs has at least one label (either Tk or ttk). There is really nothing special about the program at this point. However, in the support module I play all kinds of games with everything there. Bottom right is shown an idea of what you can expect from the finished code.

Bienvenue, mes amis. J'espère que le mois de mai vous trouvera tous en bonne santé, riches et sages. Ou du moins en bonne santé.

Ce mois-ci, je vais faire un autre article PAGE, mais ce que je vais présenter sera directement lié à la programmation Python/Tkinter, donc je pense que ce sera un bon article pour vous tous.

Quoi qu'il en soit, commençons.

Je vais commencer par une capture d'écran (ci-dessous) du programme tel qu'il apparaît dans le concepteur PAGE. Il ne s'agit en fait que du formulaire Toplevel, d'un TButton, d'un TLabelframe contenant 12 TRadiobuttons et d'un widget TNotebook. J'ai édité le TNotebook pour qu'il ait 4 onglets et j'ai placé une étiquette assez longue sur chacun d'entre eux. Et chacun des onglets a au moins une étiquette (soit Tk soit ttk).

À ce stade, le programme n'a vraiment rien de spécial. Cependant, dans le module de support, je joue à toutes sortes de jeux avec tout ce qui s'y trouve.

En bas à droite se trouve une idée de ce que vous pouvez attendre du code fini.

I hope that this is already giving you some ideas of how this might be useful to you in your own programs. It’s actually very easy to do and, with the theme that I’ve created, you can customize the theme package to suit your moods. We’ll go into the theme package more next month. For now, let’s look at how to change the position of the Tabs on the TNotebook. The TNotebook has a little known (well, probably little known to most Tkinter programmers anyway) option that allows the programmer to set the position of the Tab portion of the TNotebook widget. It’s part of the ttk Style options. Unfortunately, the Tcl man page for the TNotebook widget mentions that only the ability to set the position is available. It says nothing about what the various “legal” settings are. So, we’ll start with the actual function that does all the work (see next page, top right). So the first thing that needs to happen is to create an object that inherits from the ttk.Style base object. After many hours of struggling to come up with a name for my version of the object, I finally settled on “style”. Pretty cool, huh? Anyway, that joke probably fell flat, so we’ll move on.

J'espère que cela vous donne déjà quelques idées sur la façon dont cela pourrait vous être utile dans vos propres programmes. C'est en fait très facile à faire et, avec le thème que j'ai créé, vous pouvez personnaliser le paquet des thèmes en fonction de vos humeurs. Nous reviendrons plus en détail sur le thème le mois prochain. Pour l'instant, voyons comment changer la position des onglets sur le TNotebook.

Le TNotebook dispose d'une option peu connue (enfin, probablement peu connue de la plupart des programmeurs Tkinter) qui permet au programmeur de définir la position de la partie Tab du widget TNotebook. Elle fait partie des options de ttk Style. Malheureusement, la page du manuel Tcl pour le widget TNotebook mentionne que seule la possibilité de définir la position est disponible. Elle ne dit rien sur les différents paramètres « légaux ». Nous allons donc commencer par la fonction qui fait tout le travail (voir page suivante, en haut à droite).

La première chose à faire est donc de créer un objet qui hérite de l'objet de base ttk.Style. Après de nombreuses heures passées à chercher un nom pour ma version de l'objet, j'ai finalement opté pour « style ». Plutôt cool, non ? Quoi qu'il en soit, cette blague n'est probablement pas très bonne et nous allons donc passer à autre chose.

The next part of the function is probably not useful to this particular program, since all the decisions as to the position are provided by the TRadiobuttons. However, if you are going to add this function to one of your programs, you might want to keep it in, since mistakes are easy to make. The positions list is provided to verify that the passed parameter is actually one of the “legal” positions. We check to see if it is a member of the positions list, and if so, we use the Style.configure command. The syntax is: style.configure(TWidget name, StyleOption = Value, …) Then, the elif catches a nonvalid setting, prints a message to the terminal and “resets” the TNotebook position setting back to the default (which is the North West corner of the widget) just in case there had been some valid changes previous to this call. That’s the entire magic that has rarely been documented. The next function that we will take a look at is the callback function that is called whenever a TRadiobutton is clicked. Just so you know, all the TRadiobuttons have the same callback and the values of the TRadiobuttons are set 1 to 12. This makes it easy to use an if tree. It would be just as easy to use the switch case tree, but since that is available only from 3.10 forward, I decided to stick with the if tree (see code right).

La partie suivante de la fonction n'est probablement pas utile pour ce programme-ci, puisque toutes les décisions relatives à la position sont fournies par les TRadiobuttons. Cependant, si vous avez l'intention d'ajouter cette fonction à l'un de vos programmes, vous devriez la conserver, car il est facile de commettre des erreurs.

La liste des positions est fournie pour vérifier que le paramètre passé est bien l'une des positions « légales ». Nous vérifions si le paramètre fait partie de la liste des positions et, si c'est le cas, nous utilisons la commande Style.configure. La syntaxe est la suivante :

style.configure(TWidget name, StyleOption = Value, …)

Ensuite, la commande elif détecte un paramètre non valide, imprime un message sur le terminal et « réinitialise » le paramètre de position du TNotebook à la valeur par défaut (qui est le coin nord-ouest du widget), juste au cas où il y aurait eu des changements valides avant cet appel.

C'est là toute la magie qui a rarement été documentée.

La fonction suivante que nous allons examiner est la fonction de rappel qui est appelée chaque fois qu'on clique sur TRadiobutton. Pour votre information, tous les TRadiobuttons ont la même fonction de rappel et les valeurs des TRadiobuttons sont comprises entre 1 et 12. Il est donc facile d'utiliser un arbre if. Il serait tout aussi facile d'utiliser l'arbre switch case, mais comme il n'est disponible qu'à partir de la version 3.10, j'ai décidé de m'en tenir à l'arbre if (voir le code à droite).

I deleted many of the elif statements since they are pretty much all the same thing with the only thing changing is the position. You might also notice that each of the if/elif statements has two set tab statements. The first is to set the position to either “e” or “n” before the actual final position is set. This is because when I was testing the program, if I went from a position on the top or bottom of the TNotebook directly to one on the right or left, the full tab set would not show up. The same if I went from the right or left to one on the right or left. I’m fairly certain that’s a bug in the ttk code. I can understand why it might have been overlooked by the original programmers of the TNotebook widget. How often would ANYONE create a program to walk the tabs around the edges of the widget. Besides me, right? Another thing you might have noticed is that the tabs are set to an interesting color set. I just put up a new post on my website (thedesignatedgeek.xyz) that explains the process, but I’ll go over it quickly here. I use another function to take care of this and it uses more ttk Styling “magic”. I called the function setup_base_style() (code shown top right).

J'ai supprimé un grand nombre d'instructions elif, car elles sont pratiquement toutes identiques, la seule chose qui change étant la position.

Vous remarquerez également que chacune des instructions if/elif comporte deux instructions set tab. La première consiste à définir la position sur « e » ou « n » avant que la position finale ne soit définie. En effet, lorsque j'ai testé le programme, si je passais d'une position en haut ou en bas du TNotebook directement à une position à droite ou à gauche, l'ensemble des onglets n'apparaissait pas. Il en allait de même si je passais d'une position à droite ou à gauche à une position à droite ou à gauche. Je suis presque certain qu'il s'agit d'un bogue dans le code ttk. Je peux comprendre que les programmeurs originaux du widget TNotebook l'aient négligé. Combien de fois N'IMPORTE QUI créerait un programme pour faire marcher les onglets sur les bords du widget. À part moi, n'est-ce pas ?

Une autre chose que vous avez peut-être remarquée, c'est que les onglets sont réglés sur un jeu de couleurs intéressant. Je viens de publier un nouvel article sur mon site Web (thedesignatedgeek.xyz) qui explique le processus, mais je vais le passer rapidement en revue ici. J'utilise une autre fonction pour m'occuper de cela et elle fait appel à la « magie » de ttk Styling. J'ai appelé la fonction setup_base_style() (code en haut à droite).

Again, we create an instance of the ttk.style object and, this time, we apply a map which is used mostly when we want to deal with colors. Basically, we assign a list of tuples to both the background and foreground colors. There are three states that we deal with here. They are selected, active, and !active (or not active). As you might suspect, the selected state is the tab that is currently selected and its page (actually a TFrame) is the one that is currently shown. The active state is triggered when the mouse cursor is hovering over that tab, and the !active state is when any of the other tabs are not in one of the other two states. So the actual selected tab is the one in the darker gray, the active tab is the one in the light gray and the !active tabs are the ones in sandybrown color. The setup_base_style is called from the startup menu. For those who don’t remember what the startup function is or where it is being called from, this is a function that allows any variables or functions to be called before the program is actually shown to the user and the program goes into the Tkinter mainloop function.

Nous créons à nouveau une instance de l'objet ttk.style et, cette fois, nous appliquons une carte qui est utilisée principalement lorsque nous voulons traiter des couleurs.

Fondamentalement, nous assignons une liste de tuples aux couleurs d'arrière-plan et d'avant-plan. Nous traitons ici trois états. Il s'agit de sélectionné, actif et !actif (ou non actif). Comme vous vous en doutez, l'état sélectionné correspond à l'onglet actuellement sélectionné et sa page (en fait une TFrame) est celle qui est actuellement affichée. L'état actif est déclenché lorsque le curseur de la souris survole cet onglet, et l'état !actif est déclenché lorsque l'un des autres onglets n'est pas dans l'un des deux autres états.

Ainsi, l'onglet sélectionné est celui qui est en gris plus foncé, l'onglet actif est celui qui est en gris clair et les onglets !actifs sont ceux qui sont en couleur marron sable.

Setup_base_style est appelé depuis le menu de démarrage. Pour ceux qui ne se souviennent pas de ce qu'est la fonction de démarrage ou de l'endroit où elle est appelée, il s'agit d'une fonction qui permet d'appeler n'importe quelle variable ou fonction avant que le programme ne soit réellement montré à l'utilisateur et que le programme n'entre dans la fonction mainloop de Tkinter.

The first few lines simply set up some general styling things (which we’ll discuss next month) and calls an imported Python module that I created and named mystyles_dark. This was an experiment I played around with back in December 2022. The idea was to create a Python based Theme for Tkinter programs. If you remember, a ttk Theme is simply a collection of styles that apply to various ttk widgets. I never got around to finishing that project, since once I got the basics of getting the styles for various widgets going, I then put the Python file on the back burner and dived head first into writing a true Tcl/Tk theme in Tcl. (That was an experience, let me tell you! Well, actually that story is going in a blog on my website.) Anyway, I digress. The Python style module has only one function, which is create_styles() which handles all of the stylings. It requires the style object (in this case sty (actually a better name than style, huh? Less to type!)). By calling it, all the widgets it has code for (most of the ttk library) is now styled to a fairly dark color. I then grab the background color from the Python styling library and assign that to a global variable (background1). Then I call the TNotebook Tab styling routine. The frames that make up the “pages” of the TNotebook, are coloured by calling the function color_notebook_pages(). I then set the background through style.configure to be the same background as the rest of the project. All the labels, since I mix Tk Labels and ttk.TLabels on the pages of the TNotebook need to be set to proper background and foreground colors, which is what the function fix_labels() does. Finally, I make sure that the Tabs positions are set to the default position and set the title for the project and center it into the screen (code shown top right).

Les premières lignes mettent simplement en place quelques éléments de style généraux (dont nous parlerons le mois prochain) et appellent un module Python importé que j'ai créé et nommé mystyles_dark. Il s'agit d'une expérience avec laquelle j'ai joué en décembre 2022. L'idée était de créer un thème basé sur Python pour les programmes Tkinter. Si vous vous souvenez, un thème ttk est simplement une collection de styles qui s'appliquent à divers widgets ttk. Je n'ai jamais pu terminer ce projet, car une fois que j'ai réussi à créer les styles de base pour les différents widgets, j'ai mis le fichier Python en veilleuse et j'ai plongé tête la première dans l'écriture d'un vrai thème Tcl/Tk en Tcl. (C'était une vraie expérience, croyez-moi ! En fait, cette histoire va faire l'objet d'un blog sur mon site Web). Mais je m'éloigne du sujet. Le module de style Python n'a qu'une seule fonction, create_styles(), qui gère tous les styles. Elle nécessite l'objet style (dans ce cas sty (en fait un meilleur nom que style, hein ? Moins à taper !)). En l'appelant, tous les widgets pour lesquels il a du code (la plupart de la bibliothèque ttk) sont maintenant stylisés dans une couleur assez sombre. Je récupère ensuite la couleur d'arrière-plan de la bibliothèque de style Python et je l'affecte à une variable globale (background1). J'appelle ensuite la routine de stylisation de l'onglet TNotebook. Les cadres qui constituent les « pages » du TNotebook sont colorés en appelant la fonction color_notebook_pages(). Je règle ensuite l'arrière-plan par le biais de style.configure pour qu'il soit le même que celui du reste du projet. Toutes les étiquettes, puisque je mélange les Tk Labels et les ttk.TLabels sur les pages du TNotebook, doivent être colorées avec les couleurs d'arrière-plan et d'avant-plan appropriées, ce que fait la fonction fix_labels(). Enfin, je m'assure que la position des onglets est réglée sur la position par défaut, je définis le titre du projet et je le centre dans l'écran (code affiché en haut à droite).

We’ll talk about the Python styling module next month (actually I’m going to start it later this afternoon, but you won’t get to see it until June). One note on the styling module, it requires an empty file named “shared.py” to share information between the modules and to provide the temporary global images for some graphic stuff. Again, more on that next month. LATE NOTE: After I wrote the article, I went back and looked at the mystyles.dark module. I said that pretty much as soon as I had gotten it to its current state, I pushed it onto the back burner in order to work on the tcl theme file. When I looked with a bit of a critical eye, I noticed that the module was missing many ttk widgets and what was there was so very minimal that it was pretty much useless outside of setting background/foreground for SOME widgets. So over the past few days, I’ve modified it pretty heavily. The version that I used in the sample program for the article was 2.04. The modifications are now up to 2.05.7𝛽 . I’ve replaced the original in the repository with the latest. There are a couple of additional functions in the module beyond the create_styles() function. In order to properly style the TCombo box (at least in my mind), the dropdown portion needs to have the same background and foreground as the entry field. To do that, however, there needs to be a couple of calls that require the options to know the root or Toplevel widget.

Nous parlerons du module de style Python le mois prochain (en fait, je vais le commencer plus tard dans l'après-midi, mais vous ne le verrez pas avant le mois de juin). Une remarque sur le module de style, il nécessite un fichier vide nommé « shared.py » pour partager les informations entre les modules et fournir les images globales temporaires pour certaines choses graphiques. Encore une fois, plus d'informations à ce sujet le mois prochain.

NOTE TARDIVE :

Après avoir écrit cet article, je suis retourné voir le module mystyles.dark. J'ai dit qu'à peu près dès que je l'avais mis dans son état actuel, je l'avais mis en veilleuse pour travailler sur le fichier de thème tcl. Quand je l'ai regardé avec un peu d'esprit critique, j'ai remarqué que le module manquait de nombreux widgets ttk et que ce qu'il y avait était si minime qu'il était pratiquement inutile en dehors de la définition de l'arrière-plan et de l'avant-plan pour CERTAINS widgets. Ces derniers jours, j'ai donc modifié le module en profondeur. La version que j'ai utilisée dans le programme d'exemple de l'article était la 2.04. Les modifications portent maintenant sur la version 2.05.7𝛽 . J'ai remplacé l'original dans le dépôt par la dernière version. Il y a quelques fonctions supplémentaires dans le module en plus de la fonction create_styles(). Afin de styliser correctement la boîte TCombo (du moins dans mon esprit), la partie déroulante doit avoir le même arrière-plan et le même avant-plan que le champ de saisie. Pour ce faire, cependant, il doit y avoir quelques appels qui exigent que les options connaissent le widget racine ou Toplevel.

So, there is a new function that is called add_options(toplevel) and requires the toplevel name. For use with PAGE, simply send in _top1 or whatever your toplevel name is. The other is a simple function called get_version(), which just returns the version of the module. As I usually do, I’ve created a repository on my GitHub page at https://github.com/gregwa1953/FCM193. It will contain the source code to create this month’s project including the PAGE .tcl file, the PAGE python modules and the Python styling module (such as it is). Until next time, as always; stay safe, healthy, positive and creative!

Il existe donc une nouvelle fonction appelée add_options(toplevel) qui requiert le nom du toplevel. Pour une utilisation avec PAGE, il suffit d'envoyer _top1 ou tout autre nom de toplevel. L'autre fonction est une simple fonction appelée get_version(), qui renvoie simplement la version du module.

Comme je le fais habituellement, j'ai créé un dépôt sur ma page GitHub à https://github.com/gregwa1953/FCM193. Il contiendra le code source pour créer le projet de ce mois-ci, y compris le fichier PAGE .tcl, les modules python pour PAGE et le module de style Python (tel qu'il est).

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

issue193/python.txt · Dernière modification : 2023/05/31 12:15 de auntiee