Outils pour utilisateurs

Outils du site


issue207:python

Simple Calculator in PAGE Greetings again fellow Sentient Lifeforms. Things here at landing pad 2997 on Terra haven't calmed down at all since last month. If anything, things are even busier. It looks like (at this time, Friday 5 July) that we will be having an unwanted visitor by the name of Hurricane Beryl. At this point, the chances are really good (or bad if you wish) that we will get at least a “drive by” visit. I’m going to have to get the ground crew to make sure the ship is lashed down and secure. However, I’m not going to let that keep me from sharing information with you. This month, I’m going to take you through creating a simple calculator in PAGE 8.0, Tkinter. Why? Well, in the last month, I’ve seen two different articles about creating a simple calculator in straight Tkinter and in Wxpython, but nothing about using a great GUI designer like PAGE (and one of them was behind a paywall (ICK)), so I thought I’d throw my two cents into the mix. Within the article, I’ll show you a couple of tricks that can be used within PAGE, or from just Tkinter if you want to “do it the hard way”.

Calculatrice simple dans PAGE

Re-bonjour à tous les formes de vie sensibles. Les choses ici, sur la plateforme d'atterrissage 2997 de Terra, ne se sont pas du tout calmées depuis le mois dernier. Au contraire, l'activité est encore plus intense. Il semble (à cette heure, vendredi 5 juillet) que nous aurons un visiteur indésirable du nom de l'ouragan Beryl. À ce stade, les chances sont très bonnes (ou mauvaises si vous le préférez) que nous recevions au moins une courte visite de la dame. Je vais devoir demander à l'équipe au sol de s'assurer que le bateau est bien arrimé et sécurisé. Mais cela ne m'empêchera pas de partager des informations avec vous.

Ce mois-ci, je vais vous aider à créer une simple calculatrice avec PAGE 8.0, Tkinter. Pourquoi ? Eh bien, le mois dernier, j'ai vu deux articles différents sur la création d'une calculatrice simple en Tkinter et en Wxpython, mais rien sur l'utilisation d'un excellent concepteur d'interface graphique comme PAGE (et l'un d'entre eux était derrière un paywall (berck)), alors j'ai pensé que je devais jeter mes deux centimes dans le mélange.

Dans cet article, je vous montrerai quelques astuces qui peuvent être utilisées avec PAGE, ou simplement avec Tkinter si vous voulez « faire les choses à la dure ».

Just because I’m a nice guy (according to some people), I’ve set up a github repository for you that you can download the entire project which includes all the PAGE files and Python files – so you don’t really have to deal with PAGE if you don’t want to. The URL for the repository can be found at the end of the article. Basic Requirements So, the basic requirements for our project will be to create a “4 banger” calculator. Since the phrase “4 banger” goes back to the early days of electronic calculators (1970s), you might not be aware of what that means. Simply put, it’s a calculator that does only addition, subtraction, multiplication and division. That’s it. No mod function, no parentheses, not even a square root function or percentage. Of course, you can add these functions yourself if you want, but I wanted to create a really quick project that wouldn’t make my article take up half of the magazine. Of course, since it’s me, we will use PAGE 8.0 to design the GUI form. I’m not even going to go into depth on creating the form in PAGE, just some of the highlights. We won’t be using any graphics, only text on the buttons. The only “special characters” we will be using are the “<X]” character for the clear key (U+232B), and the “÷” for the division key (U+00F7).

Juste parce que je suis un gars sympa (selon certaines personnes), j'ai mis en place un dépôt github pour vous permettre de télécharger le projet entier qui comprend tous les fichiers PAGE et les fichiers Python - ainsi vous n'avez pas vraiment à vous occuper de PAGE si vous ne le souhaitez pas. L'URL du dépôt se trouve à la fin de l'article.

Exigences de base

Les exigences de base de notre projet seront donc de créer une calculatrice « 4 banger ». Comme l'expression « 4 banger » remonte aux premiers jours des calculatrices électroniques (les années 1970), il se peut que vous ne sachiez pas ce que cela signifie. Pour faire simple, il s'agit d'une calculatrice qui ne fait que des additions, des soustractions, des multiplications et des divisions. C'est tout. Pas de fonction mod, pas de parenthèses, pas même de fonction racine carrée ou de pourcentage. Bien sûr, vous pouvez ajouter ces fonctions vous-même si vous le souhaitez, mais je voulais créer un projet vraiment rapide de sorte que mon article ne prenne pas la moitié du magazine.

Bien sûr, puisque c'est moi, nous utiliserons PAGE 8.0 pour concevoir le formulaire de l'interface graphique. Je ne vais même pas m'étendre sur la création du formulaire dans PAGE, mais seulement sur certains points importants. Nous n'utiliserons pas de graphiques, seulement du texte sur les boutons. Les seuls « caractères spéciaux » que nous utiliserons sont le caractère « <X] » pour la touche d'effacement (U+232B) et le « ÷ » pour la touche de division (U+00F7).

Since we will be using PAGE 8.0, we’ll use one of the themes I created for it named “cornsilk-light”. Since we will be concentrating more on the Python code instead of the PAGE portion, I’ll give you a small function that will modify that theme to create a bold 18-point font that will apply to all the TButtons, and a slightly darker background to make them stand out from the background of the form a little bit. Our callbacks for the buttons will be somewhat on the special side, since I’m going to use the lambda function to send a “key definition” via the command attribute for each of the TButtons. The finished project should look something like this… Creating the PAGE GUI So, we’ll need to create a folder to hold our PAGE project, and the themes folder to hold the cornsilk-light theme files. Then copy from the PAGE 8.0 themes folder (or from the repository files) the cornsilk-light.tcl, and the entire cornsilk folder into a themes folder. Now, in a terminal window type $ page calc1

Comme nous allons utiliser PAGE 8.0, nous allons utiliser l'un des thèmes que j'ai créé pour lui, nommé « cornsilk-light ». Comme nous allons nous concentrer sur le code Python plutôt que sur la partie PAGE, je vais vous donner une petite fonction qui va modifier ce thème pour créer une police de 18 points en gras qui s'appliquera à tous les TButtons et un fond légèrement plus sombre pour les faire ressortir un peu de l'arrière-plan du formulaire.

Pour les boutons, nos fonctions de rappel seront un peu spéciales, puisque je vais utiliser la fonction lambda pour envoyer une « définition de clé » via l'attribut command à chacun des TButtons.

Le projet fini devrait ressembler à ceci…

Création de l'interface graphique PAGE

Nous allons donc devoir créer un dossier pour contenir notre projet PAGE et le dossier themes pour contenir les fichiers du thème cornsilk-light. Copiez ensuite le fichier cornsilk-light.tcl depuis le dossier themes de PAGE 8.0 (ou depuis les fichiers du dépôt), ainsi que l'ensemble du dossier cornsilk, dans le dossier themes. Maintenant, dans une fenêtre du terminal, tapez

$ page calc1

Now, set your Toplevel form to width=359 and height to 467. Set the title to “Calc1”. Make sure that you are in the Absolute mode so the form won’t resize. Add a TLabel widget at x=2, y=60, with a height of 50 and a width of 356. Set the background color to “white”, the relief to ‘sunken’, anchor to “w”, the textvar to “Display”, and the font to ‘DejaVu Sans’, size=20 and weight=bold. Next, place a TButton widget at x=10, y=140, height=49 and width=62. Then set the text to “7”. Finally set the command attribute to “lambda : on_numKey(7)”. The theme will take care of all of the other attributes, and we’ll override some of those when we create our theme override later on in the _support module. Now, add 10 more TButton widgets aligning them into a “keypad” orientation as in the image above. Set the text to the proper number for that key and the command to “lambda : on_numKey(X)” where X is the number of the key (or for the period key simply ‘.’. Be sure to use single quotes when using the PAGE command attribute text box). Now, add 6 more TButtons, and set their text as seen in the image above. For the clear and divide keys, there’s a file in the repo called symbols.txt that has the two symbols. Just copy each and paste them into the text attribute column.

Maintenant, réglez votre formulaire Toplevel sur une largeur de 359 et une hauteur de 467. Fixez le titre à « Calc1 ». Assurez-vous que vous êtes en mode Absolute afin que le formulaire ne soit pas redimensionné.

Ajoutez un widget TLabel à x=2, y=60, avec une hauteur de 50 et une largeur de 356. Réglez la couleur d'arrière-plan sur « white », le relief sur « sunken », l'ancrage sur « w », la textvar sur « Display » et la police sur « DejaVu Sans », size=20 et weight=bold.

Ensuite, placez un widget TButton à x=10, y=140, height=49 et width=62. Puis, définissez le texte à « 7 ». Enfin, définissez l'attribut command à « lambda : on_numKey(7) ». Le thème s'occupera de tous les autres attributs et nous remplacerons certains d'entre eux lorsque nous créerons notre thème plus tard dans le module _support.

Maintenant, ajoutez 10 autres widgets TButton en les alignant dans une orientation « clavier » comme dans l'image ci-dessus. Définissez le texte avec le numéro approprié pour cette touche et la commande à « lambda : on_numKey(X) » où X est le numéro de la touche (ou simplement '.' pour la touche point). Veillez à utiliser des guillemets simples lorsque vous utilisez la zone de texte de l'attribut de commande PAGE).

Ajoutez maintenant 6 autres boutons TB et définissez leur texte comme indiqué dans l'image ci-dessus. Pour les touches clear et divide, il y a dans le dépôt un fichier appelé symbols.txt qui contient les deux symboles. Il suffit de les copier et de les coller dans la colonne des attributs de texte.

At this point, the final step is to enter each of the command line attributes. The one for the Divide button would be “lambda : on_funcKey(‘Divide’)”. From there the text for the command attribute sets would be: lambda : on_funcKey(‘Mult’) lambda : on_funcKey(‘Sub’) lambda : on_funcKey(‘Add’) lambda : on_funcKey(‘Equal’) lambda : on_funcKey(‘Clear’) Once you have all your keys defined, save your project as “calc1” and generate the GUI.py file and the Support module. Your Toplevel should look something like this… You can close PAGE at this point. Again, none of the buttons have bold font or a background other than the cornsilk3 colour, which the theme contains. The Code Now we can begin to create our functions and callbacks in the support module (“calc1_support.py”). PAGE created the majority of the program for us, but we still need to flesh the skeletons out.

À ce stade, la dernière étape consiste à saisir chacun des attributs de la ligne de commande. Celui du bouton Diviser serait « lambda : on_funcKey('Divide') ». À partir de là, le texte des ensembles d'attributs de commande sera le suivant :

lambda : on_funcKey('Mult') lambda : on_funcKey('Sub') lambda : on_funcKey('Add') lambda : on_funcKey('Equal') lambda : on_funcKey('Clear')

Une fois que vous avez défini toutes vos clés, sauvegardez votre projet sous le nom « calc1 » et générez le fichier GUI.py et le module Support.

Votre Toplevel devrait ressembler à ceci…

Vous pouvez fermer PAGE à ce stade. Encore une fois, aucun des boutons n'a de police en gras ou d'arrière-plan autre que la couleur cornsilk3, qui se trouve dans le thème.

Le code

Nous pouvons maintenant commencer à créer nos fonctions et nos rappels dans le module de support (« calc1_support.py »).

PAGE a créé la majorité du programme pour nous, mais nous devons encore étoffer les squelettes.

First, we need to add an import statement. Near the top of the file are all of the import statements. Just after the “from tkinter.constants import *” line, you need to add from tkinter.font import Font This is because we will be defining a “custom” font in a little bit. Next, scroll down to the main function. PAGE already created this for us, but we need to run a few extra commands before the form is displayed to you or your user. Just before the last line of the main function, add a line that contains “startup()”. I’ve included the function below with only the line to add in black (next page, top right). At this point, we need to add the startup function code. I usually put this just after the main function. The first task we do is clear the ‘Display’ Label widget by calling the .set() method of the Label widget. Then we define a global variable named “dbuf” and set it to an empty string. After that, we call a function called set_button_fonts(), which will create a custom theme for our buttons and finally set the title for the form (code shown above).

Tout d'abord, nous devons ajouter une déclaration d'importation. Toutes les instructions d'importation se trouvent en haut du fichier. Juste après la ligne « from tkinter.constants import * », vous devez ajouter

from tkinter.font import Font

C'est parce que nous allons définir une police « personnalisée » dans un petit moment.

Ensuite, descendez jusqu'à la fonction principale. PAGE l'a déjà créée pour nous, mais nous devons exécuter quelques commandes supplémentaires avant que le formulaire ne soit affiché pour vous ou votre utilisateur. Juste avant la dernière ligne de la fonction principale, ajoutez une ligne contenant « startup() ». J'ai inclus la fonction ci-dessous avec seulement la ligne à ajouter en noir (page suivante, en haut à droite).

À ce stade, nous devons ajouter le code de la fonction de démarrage. J'ai l'habitude de le placer juste après la fonction principale.

La première chose à faire est d'effacer le widget Label 'Display' en appelant la méthode .set() du widget Label. Nous définissons ensuite une variable globale nommée « dbuf » et lui attribuons la valeur d'une chaîne vide. Ensuite, nous appelons une fonction appelée set_button_fonts(), qui créera un thème personnalisé pour nos boutons, et enfin nous définissons le titre du formulaire (code ci-dessus).

Here is the set_button_fonts() function. As you can see from the comments, we create an instance of the ttk.style object, define a new font using “DejaVu Sans”, font size 18 points and weight bold, and assign that a name of “myFont”. Then we call the style.configuration method to set the font to myFont and the background to “cornsilk4” to every TButton widget in the project. Finally we call the update function for the Toplevel to make sure it is done before we show it to the user. At this point, we have only two more functions to deal with. They are the callbacks for the buttons that make up the “numKey” group and for those that make up the “funcKey” group. The on_numKey callback is REALLY easy (below). We simply append the value that is sent into the on_numKey function from the button to the variable dbuf and display that in the TLable widget. When we set the command function for the number keys (and the period key), we use the lambda function that allows the command function to send a value into the callback. (Normally callbacks can not include any parameters. We can get around this by using the lambda function). So for the # 4 key, the command attribute would be… lambda : on_numKey(4)

Voici la fonction set_button_fonts(). Comme vous pouvez le voir dans les commentaires, nous créons une instance de l'objet ttk.style, définissons une nouvelle police en utilisant « DejaVu Sans », une taille de police de 18 points et un poids gras, et lui attribuons le nom de « myFont ». Nous appelons ensuite la méthode style.configuration pour attribuer la police myFont et l'arrière-plan « cornsilk4 » à chaque widget TButton du projet. Enfin, nous appelons la fonction de mise à jour du Toplevel pour nous assurer qu'il est terminé avant de le montrer à l'utilisateur.

À ce stade, il ne nous reste plus que deux fonctions à gérer. Il s'agit des rappels pour les boutons qui composent le groupe « numKey » et pour ceux qui composent le groupe « funcKey ». Le rappel on_numKey est VRAIMENT facile (ci-dessous).

Nous ajoutons simplement la valeur envoyée par le bouton dans la fonction on_numKey à la variable dbuf et l'affichons dans le widget TLable. Lorsque nous définissons la fonction de commande pour les touches numériques (et la touche point), nous utilisons la fonction lambda qui permet à la fonction de commande d'envoyer une valeur dans le rappel. (Normalement, les rappels ne peuvent pas inclure de paramètres. Nous pouvons contourner ce problème en utilisant la fonction lambda). Ainsi, pour la touche 4, l'attribut de commande serait…

lambda : on_numKey(4)

When it gets to the on_numKey, it is sent in to the *args, which contains all the arguments as a list. Since we are sending in only one value, it will come in as args[0]. That is converted into a string. Unfortunately, the on_funcKey is a bit more complicated, but not horribly so. In fact it’s more repetitive than complicated. Rather than the “normal” if | elif |else tree, I decided to use the newer match case tree. The first thing we do is assign the incoming string from the button command to a variable called which. Then the match compares this value to each of the case statements. The cases for “Add”, “Sub”, “Mult” and “Divide” are almost the same, just assigning a different character to match the function to the dbuf global variable. This time I decided to use the f-string method. So for the “Add” function we add a “+” to the string and so on. Then we send it to the TLabel widget to show to the user. For the Clear function, we simply set the TLabel widget and the dbuf variable to an empty string (shown right).

Lorsqu'elle arrive à on_numKey, elle est envoyée dans *args, qui contient tous les arguments sous forme de liste. Comme nous n'envoyons qu'une seule valeur, elle sera envoyée sous la forme args[0]. Cette valeur est convertie en chaîne de caractères.

Malheureusement, le on_funcKey est un peu plus compliqué, mais pas terriblement. En fait, il est plus répétitif que compliqué. Plutôt que l'arborescence « normale » if | elif |else, j'ai décidé d'utiliser le nouvel arborescence match case.

La première chose que nous faisons est d'assigner la chaîne de caractères entrante de la commande du bouton à une variable appelée which. Ensuite, match compare cette valeur à chacune des instructions case. Les cas pour « Add », « Sub », « Mult » et « Divide » sont presque les mêmes, il suffit d'assigner un caractère différent pour faire correspondre la fonction à la variable globale dbuf. Cette fois, j'ai décidé d'utiliser la méthode f-string.

Ainsi, pour la fonction « Add », nous ajoutons un « + » à la chaîne et ainsi de suite. Nous l'envoyons ensuite au widget TLabel pour qu'il l'affiche à l'utilisateur.

Pour la fonction Clear, nous définissons simplement le widget TLabel et la variable dbuf à une chaîne vide (illustrée à droite).

Now… the part of the function that makes everything work. That’s the “Equal” case. When the user clicks on the Equal button, we simply take the string that we’ve been building all along and then use python’s eval function. So if the user clicks the buttons “2”, “+”, “2”, and then presses the equal key, the dbuf variable would be “2+2” and the eval then can deal this as a math statement. Therefore, the answer is (of course) 4. Simple, but in no way, shape or form is it bullet-proof. I didn’t include any kind of error checking. I did say at the beginning that it was a SIMPLE calculator program. You can find the repository at https://github.com/gregwa1953/FCM207 which contains all the information that you need to run the program, including the PAGE files, the theme folder and files, and the Python code. Until next time, as always; stay safe, healthy, positive and creative!

Maintenant… la partie de la fonction qui fait que tout fonctionne. C'est le cas « Equal ». Lorsque l'utilisateur clique sur le bouton « Equal », nous prenons simplement la chaîne que nous construisons depuis le début et nous utilisons la fonction eval de Python.

Ainsi, si l'utilisateur clique sur les boutons « 2 », « + », « 2 », puis appuie sur la touche « Equal », la variable dbuf sera « 2+2 » et la fonction eval pourra la traiter comme un énoncé mathématique. Par conséquent, la réponse est (bien sûr) 4.

C'est simple, mais ce n'est en aucun cas à l'épreuve des balles. Je n'ai inclus aucun genre de contrôle d'erreur. J'ai bien précisé au début qu'il s'agissait d'un programme de calculatrice SIMPLE.

Vous pouvez trouver le dépôt à https://github.com/gregwa1953/FCM207 qui contient toutes les informations dont vous avez besoin pour exécuter le programme, y compris les fichiers PAGE, le dossier et les fichiers du thème, et le code Python.

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

issue207/python.txt · Dernière modification : 2024/07/29 17:44 de auntiee