Outils pour utilisateurs

Outils du site


issue182:python

Différences

Ci-dessous, les différences entre deux révisions de la page.

Lien vers cette vue comparative

Les deux révisions précédentesRévision précédente
Prochaine révision
Révision précédente
issue182:python [2022/06/27 14:16] d52frissue182:python [2022/06/30 15:51] (Version actuelle) andre_domenech
Ligne 1: Ligne 1:
 **Being from Texas, most of us here have a tendency to “change horses in midstream” as the saying goes, and this month, I’m afraid I’m going to have to do just that. I was planning to continue my article from last month (FCM 181) on understanding styles and themes for ttk and Tkinter, and in fact started down that path. However, in working with a user of PAGE for the last few days, trying to solve a problem, I realized that there is an issue out there, lurking and waiting to bite every programmer in their proverbial backsides who uses images and Tkinter in their program creation process. That issue is that we, as programmers, do not know in advance where our end users will run our programs from. Will it be from the Desktop, which is becoming more and more popular? Will it be from the folder that contains the source code? Even if we state how the program should be run, that doesn’t mean that our ultimate end users will pay attention to our requests/demands, and if things don’t fit their expectations, watch out for the complaints. So, in order to try to help us all be mindful of this pending issue, I’ve decided to press pause for a month and continue our discussion on Styles and Themes next month.** **Being from Texas, most of us here have a tendency to “change horses in midstream” as the saying goes, and this month, I’m afraid I’m going to have to do just that. I was planning to continue my article from last month (FCM 181) on understanding styles and themes for ttk and Tkinter, and in fact started down that path. However, in working with a user of PAGE for the last few days, trying to solve a problem, I realized that there is an issue out there, lurking and waiting to bite every programmer in their proverbial backsides who uses images and Tkinter in their program creation process. That issue is that we, as programmers, do not know in advance where our end users will run our programs from. Will it be from the Desktop, which is becoming more and more popular? Will it be from the folder that contains the source code? Even if we state how the program should be run, that doesn’t mean that our ultimate end users will pay attention to our requests/demands, and if things don’t fit their expectations, watch out for the complaints. So, in order to try to help us all be mindful of this pending issue, I’ve decided to press pause for a month and continue our discussion on Styles and Themes next month.**
 +
 +Comme la plupart de ceux qui viennent du Texas, nous avons tendance à « changer de cheval en cours de route », comme le dit le proverbe, et ce mois-ci, je crains de devoir le faire. J'avais l'intention de poursuivre mon article du mois dernier (dans le FCM n° 181) sur la compréhension des styles et des thèmes pour ttk et Tkinter, et j'ai en fait commencé sur cette voie. Cependant, en travaillant avec un utilisateur de PAGE ces derniers jours, pour essayer de résoudre un problème, j'ai réalisé qu'il y a un problème, qui rôde en attendant de mordre chaque programmeur dans son derrière proverbial qui utilise des images et Tkinter dans son processus de création de programme. Ce problème est que nous, en tant que programmeurs, ne savons pas à l'avance à partir de quel endroit nos utilisateurs finaux exécuteront nos programmes. Est-ce que ce sera à partir du bureau, ce qui devient de plus en plus populaire ? Sera-t-il lancé à partir du dossier qui contient le code source ? Même si nous indiquons comment le programme doit être exécuté, cela ne signifie pas que nos utilisateurs finaux prêteront attention à nos demandes/exigences, et si les choses ne correspondent pas à leurs attentes, attention aux plaintes. Ainsi, afin d'essayer de nous aider tous à être attentifs à cette question en suspens, j'ai décidé de faire une pause pendant un mois et de poursuivre notre discussion sur les styles et les thèmes le mois prochain.
 +
  
 **So what brought up this “issue”? Well, the user was trying to use a demo program that I wrote that “shows off” just a few of the capabilities of the widgets that PAGE supports. These can be broken down into 3 groups. There are the “standard” Tk widgets like standard buttons, labels and so on. Then there are the ttk Themed widgets, like the TButton, TLabel, Treeview, TCombobox, etc. Finally there are the “enhanced” widgets that usually have scrollbars built in, like the ScrolledListbox or the ScrolledText widgets. More times than not, these “enhanced” widgets are based on the “standard” Tk widgets, but a handful are based on a ttk widget. Widgets like Tk Radiobuttons and Checkbuttons have a way to change the look of how the widget appears when the program is run, which can involve using custom graphic images, one for the On state and one for the Off state, in addition to a few extra attribute settings. This allows a “normally ugly and looks like Windows 95” Tkinter program to look clean and fresh and receives a bunch of “Oohs” and “Ahhs” from the end users (and other programmers as well). So when we want to use graphics in our Tkinter programs, we have to be mindful of the location where the program will “live”, and where the ultimate end user will attempt to execute our program from.** **So what brought up this “issue”? Well, the user was trying to use a demo program that I wrote that “shows off” just a few of the capabilities of the widgets that PAGE supports. These can be broken down into 3 groups. There are the “standard” Tk widgets like standard buttons, labels and so on. Then there are the ttk Themed widgets, like the TButton, TLabel, Treeview, TCombobox, etc. Finally there are the “enhanced” widgets that usually have scrollbars built in, like the ScrolledListbox or the ScrolledText widgets. More times than not, these “enhanced” widgets are based on the “standard” Tk widgets, but a handful are based on a ttk widget. Widgets like Tk Radiobuttons and Checkbuttons have a way to change the look of how the widget appears when the program is run, which can involve using custom graphic images, one for the On state and one for the Off state, in addition to a few extra attribute settings. This allows a “normally ugly and looks like Windows 95” Tkinter program to look clean and fresh and receives a bunch of “Oohs” and “Ahhs” from the end users (and other programmers as well). So when we want to use graphics in our Tkinter programs, we have to be mindful of the location where the program will “live”, and where the ultimate end user will attempt to execute our program from.**
 +
 +Alors, qu'est-ce qui a soulevé ce « problème » ? Eh bien, l'utilisateur essayait d'utiliser un programme de démonstration que j'ai écrit et qui « montre avec brillance » seulement quelques-unes des capacités des widgets que PAGE supporte. Ceux-ci peuvent être divisés en 3 groupes. Il y a les widgets Tk « standards » comme les boutons standards, les étiquettes et ainsi de suite. Ensuite, il y a les widgets thématiques de Ttk, comme TButton, TLabel, Treeview, TCombobox, etc. Enfin, il y a les widgets « améliorés » qui intègrent généralement des barres de défilement, comme les widgets ScrolledListbox ou ScrolledText. La plupart du temps, ces widgets « améliorés » sont basés sur les widgets Tk « standards », mais certains sont basés sur un widget Ttk. Les widgets tels que les Radiobuttons et Checkbuttons de Tk peuvent modifier l'apparence du widget lorsque le programme est exécuté, ce qui peut impliquer l'utilisation d'images graphiques personnalisées, une pour l'état On et une pour l'état Off, en plus de quelques paramètres d'attributs supplémentaires. Cela permet à un programme Tkinter « normalement laid et ressemblant à Windows 95 » d'avoir un aspect propre et frais et de recevoir un tas de « Oh » et de « Ah » de la part des utilisateurs finaux (et des autres programmeurs également). Ainsi, lorsque nous voulons utiliser des graphiques dans nos programmes Tkinter, nous devons être attentifs à l'endroit où le programme « vivra », et où l'utilisateur final tentera d'exécuter notre programme.
 +
  
 **I had run into this a long time ago when I created a program for my own use, never really expecting to share it with anyone. The program uses a large number of graphic files, all .png files which are located in a sub-folder of the main source code. When the program was executed directly from the source code folder, everything worked just fine. When I tried to create a link from the Desktop that would call Python with the full path of the source code, it failed. I finally tracked it down to the path to the graphic files “couldn’t be found”. I tried a number of solutions without success until I stumbled upon a somewhat messy fix, which was to create a complete and fully qualified path which started with “/home/greg/…”. Of course, I hardcoded this in my early development, to save time and energy and eventual hair loss from my pulling them out in great handfuls. I went on with my development, not really thinking of the fact that by doing it that way, not only could I not share the program with anyone, but I couldn’t even move the program from its hard-coded location. My mind, at the time, was focused on getting the thing to work, not the sloppy programming methods I was employing. Other things came up and development of this program, which worked for the limited things I wanted to accomplish, was shelved and all of what I had learned went on that shelf as well.** **I had run into this a long time ago when I created a program for my own use, never really expecting to share it with anyone. The program uses a large number of graphic files, all .png files which are located in a sub-folder of the main source code. When the program was executed directly from the source code folder, everything worked just fine. When I tried to create a link from the Desktop that would call Python with the full path of the source code, it failed. I finally tracked it down to the path to the graphic files “couldn’t be found”. I tried a number of solutions without success until I stumbled upon a somewhat messy fix, which was to create a complete and fully qualified path which started with “/home/greg/…”. Of course, I hardcoded this in my early development, to save time and energy and eventual hair loss from my pulling them out in great handfuls. I went on with my development, not really thinking of the fact that by doing it that way, not only could I not share the program with anyone, but I couldn’t even move the program from its hard-coded location. My mind, at the time, was focused on getting the thing to work, not the sloppy programming methods I was employing. Other things came up and development of this program, which worked for the limited things I wanted to accomplish, was shelved and all of what I had learned went on that shelf as well.**
 +
 +J'ai rencontré ce problème il y a longtemps, lorsque j'ai créé un programme pour mon usage personnel, sans vraiment penser le partager avec qui que ce soit. Le programme utilise un grand nombre de fichiers graphiques, tous des fichiers .png qui se trouvent dans un sous-dossier du code source principal. Lorsque le programme était exécuté directement à partir du dossier du code source, tout fonctionnait parfaitement. Lorsque j'ai essayé de créer un lien à partir du bureau qui appellerait Python avec le chemin complet du code source, cela a échoué. J'ai finalement trouvé que le chemin des fichiers graphiques était « introuvable ». J'ai essayé un certain nombre de solutions sans succès jusqu'à ce que je tombe sur une solution un peu compliquée, qui consistait à créer un chemin complet et entièrement qualifié commençant par « /home/greg/... ». Bien sûr, j'ai codé cela en dur au début de mon développement, pour économiser du temps et de l'énergie, ainsi qu'une éventuelle perte de cheveux à force de les arracher par poignées. J'ai poursuivi mon développement, sans vraiment penser au fait qu'en procédant de cette manière, non seulement je ne pouvais pas partager le programme avec qui que ce soit, mais je ne pouvais même pas déplacer le programme de son emplacement codé en dur. À l'époque, mon esprit était concentré sur son fonctionnement et non sur les méthodes de programmation bâclées que j'employais. D'autres choses sont arrivées et le développement de ce programme, qui fonctionnait pour les choses limitées que je voulais accomplir, a été mis de côté avec tout ce que j'avais appris aussi.
 +
  
 **Jumping back to the current issue, this was one of the problems that was plaguing this user when he tried to run the demo on his Raspberry Pi from his desktop. There was one graphic in the program (while there were a number of other graphics there as well), that was causing the program to fail for him. Actually there were other images that were also a problem, but this was the first one that the program tried to load. After a long troubleshooting session, I finally realized what was going on and asked the user to try to run the program from the source code folder. He had some other issues that prevented it, but when push came to shove, it would run correctly. **Jumping back to the current issue, this was one of the problems that was plaguing this user when he tried to run the demo on his Raspberry Pi from his desktop. There was one graphic in the program (while there were a number of other graphics there as well), that was causing the program to fail for him. Actually there were other images that were also a problem, but this was the first one that the program tried to load. After a long troubleshooting session, I finally realized what was going on and asked the user to try to run the program from the source code folder. He had some other issues that prevented it, but when push came to shove, it would run correctly.
  
 Trying to remember what the ticklers in my old brain were trying to tell me about the past lessons learned, I attempted to come up with a properly “pythonic” method to dynamically set a path statement that would keep everything happy, no matter where the program was started from, and no matter where it existed. Digging into the dusty resources that I had here and out on the Internet about the issue, I threw together a very quick and VERY dirty demonstration that not only showed the issue but presented some helpful information (albeit redundant in nature) to someone wondering about a quick but clean method around the problem.** Trying to remember what the ticklers in my old brain were trying to tell me about the past lessons learned, I attempted to come up with a properly “pythonic” method to dynamically set a path statement that would keep everything happy, no matter where the program was started from, and no matter where it existed. Digging into the dusty resources that I had here and out on the Internet about the issue, I threw together a very quick and VERY dirty demonstration that not only showed the issue but presented some helpful information (albeit redundant in nature) to someone wondering about a quick but clean method around the problem.**
 +
 +Pour en revenir à la question actuelle, c'était l'un des problèmes qui se posait à cet utilisateur lorsqu'il essayait d'exécuter la démo sur son Raspberry Pi à partir de son bureau. Il y avait un fichier graphique dans le programme (et il y avait un certain nombre d'autres fichiers graphiques), qui causait l'échec de son programme. En fait, d'autres images posaient également problème, mais celle-ci était la première que le programme essayait de charger. Après une longue session de dépannage, j'ai finalement compris ce qui se passait et j'ai demandé à l'utilisateur d'essayer d'exécuter le programme à partir du dossier du code source. D'autres problèmes l'en empêchaient, mais en fin de compte, le programme s'est exécuté correctement.
 +
 +En essayant de me souvenir de ce que les chatouilles de mon vieux cerveau essayaient de me dire à propos des leçons apprises dans le passé, j'ai essayé de trouver une méthode proprement « pythonique » pour définir dynamiquement une déclaration de chemin d'accès qui rendrait tout le monde heureux, quel que soit le point de départ du programme et quel que soit son emplacement. En creusant dans les ressources poussiéreuses que j'avais ici et sur Internet à propos de ce problème, j'ai mis au point une démonstration très rapide et très sale qui non seulement montrait le problème mais présentait des informations utiles (bien que redondantes par nature) à quelqu'un qui s'interrogeait sur une méthode rapide mais propre pour contourner le problème.
 +
  
 **The Tool **The Tool
Ligne 18: Ligne 32:
  
 When run directly from the source code folder, you can see that no matter which of the 6 system calls I made, they all returned the same information, which, on many levels, was quite a comfort for me. However, when the program is run from /home or /Desktop, the difference is shown.** When run directly from the source code folder, you can see that no matter which of the 6 system calls I made, they all returned the same information, which, on many levels, was quite a comfort for me. However, when the program is run from /home or /Desktop, the difference is shown.**
 +
 +L'outil
 +
 +Puisque j'essayais de créer un outil avec une interface utilisateur graphique (GUI) pour indiquer le problème facilement, j'ai, bien sûr, rapidement créé une GUI en PAGE, sans vraiment essayer d'adhérer aux bons concepts de création d'une GUI.
 +
 +J'ai opté pour 6 appels de bibliothèque Python différents (mais très similaires) pour aider à déterminer les informations qui devront être présentées afin d'exécuter un script Python non seulement à partir du dossier du code source, mais aussi à partir de /home et /Bureau, et de partout où l'on pourrait penser à essayer d'exécuter le programme.
 +
 +Bien sûr, l'interface graphique devrait fournir une représentation graphique rapide montrant le succès ou l'échec du chargement d'une image dans un widget Tkinter ainsi qu'une indication rapide de ce que chacun des 6 appels de fonction différents a retourné, afin que je (ou n'importe qui d'autre) puisse rapidement décider d'une solution. 
 +
 +Lorsqu'il est exécuté directement à partir du dossier du code source, vous pouvez voir que, quel que soit celui des 6 appels système que j'ai faits, ils ont tous retourné la même information, ce qui, à bien des égards, m'a réconforté. Cependant, lorsque le programme est exécuté depuis /home ou /Bureau, des différences apparaîssent.
 +
  
 **Three of the system calls ended up returning the same information, and the other three returned a different result, but all three of those were consistent in their returned data. **Three of the system calls ended up returning the same information, and the other three returned a different result, but all three of those were consistent in their returned data.
Ligne 30: Ligne 55:
  
 os.path.abspath(os.getcwd())** os.path.abspath(os.getcwd())**
 +
 +Trois des appels système ont fini par renvoyer les mêmes informations, et les trois autres ont renvoyé un résultat différent, mais tous trois étaient cohérents dans les données qu'ils renvoyaient.
 +
 +Voici (page précédente, en haut à droite) un aperçu rapide et une description de chacun d'entre eux. Honnêtement, il existe des dizaines d'autres façons de faire, alors si vous voulez en essayer d'autres, n'hésitez pas. Je suis juste là pour faire circuler les idées.
 +
 +Il y a donc 4 fonctions de la bibliothèque os.path et 2 de la bibliothèque pathlib. Lorsque le programme est exécuté à partir d'un emplacement autre que le dossier source, les trois qui renvoient seulement l'emplacement d'où le programme est exécuté sont :
 +
 +os.path.abspath(nom du fichier)
 +
 +pathlib.Path().absolute()
 +
 +os.path.abspath(os.getcwd())
 +
  
 **This means that for this specific use case, these three system calls can’t be used for our purposes. **This means that for this specific use case, these three system calls can’t be used for our purposes.
Ligne 40: Ligne 78:
  
 Of course, we have to import the os and pathlib libraries into our program.** Of course, we have to import the os and pathlib libraries into our program.**
 +
 +Cela signifie que, pour ce cas d'utilisation spécifique, ces trois appels système ne peuvent pas être utilisés pour nos besoins.
 +
 +Parmi les trois choix restants, chacun d'entre eux renvoie le chemin d'accès complet à notre dossier source, ce qui est ce que nous voulons. Nous pouvons toujours l'affecter à une variable pour le chemin d'accès et ajouter le chemin d'accès à notre dossier d'images local et le nom du fichier.
 +
 +Le code
 +
 +Puisqu'il s'agit d'un programme PAGE et d'un programme très simple, j'ai décidé de placer tout le code dans une fonction appelée « startup » qui sera exécutée juste avant que l'interface graphique ne soit montrée à l'utilisateur. Il s'agit d'essayer de charger les deux images, d'obtenir le chemin d'accès à partir des 6 appels système et de charger un widget Texte et les deux étiquettes de texte dynamiques. L'appel à la fonction startup est l'avant-dernière ligne de la fonction principale fournie par PAGE.
 +
 +Bien sûr, nous devons importer les bibliothèques os et pathlib dans notre programme.
 +
  
 **def startup(): **def startup():
Ligne 54: Ligne 103:
  
 _w1.ProperPath.set(abspath1)** _w1.ProperPath.set(abspath1)**
 +
 +def startup():
 +
 +    import os, pathlib
 +
 +À ce stade, j'assigne un nom de variable (quelque peu explicite sur son rôle) à partir de chacun des 6 appels système, puis j'imprime la valeur de chacune des variables en utilisant une chaîne de caractères au format f-string (en haut à droite).
 +
 +Après avoir regardé les résultats lorsque je l'ai lancé depuis /Bureau, j'ai décidé d'utiliser ces deux variables pour fournir ce que le programme pense être l'information appropriée (localpath et abspath1). La variable localpath (localpath = os.path.dirname(os.path.abspath(__file__))) est l'information que nous allons finalement utiliser. Mais je m'avance un peu et j'ai gâché la surprise. Quoi qu'il en soit, j'utilise ensuite la méthode .set() des deux étiquettes de texte dans le formulaire.
 +
 +# Charger les deux étiquettes avec les chemins
 +
 +_w1.LocalPath.set(localpath)
 +
 +_w1.ProperPath.set(abspath1)
 +
  
 **At this point, I can define the image name, which includes the path (located from the source directory) and filename. **At this point, I can define the image name, which includes the path (located from the source directory) and filename.
Ligne 68: Ligne 132:
 •  The graphic exists, then •  The graphic exists, then
 there won’t be a problem loading that graphic. I know that I’m being overly optimistic, but that’s just me.** there won’t be a problem loading that graphic. I know that I’m being overly optimistic, but that’s just me.**
 +
 +A ce stade, je peux définir le nom de l'image, qui comprend le chemin (situé depuis le répertoire source) et le nom du fichier.
 +
 +# définir le nom de l'image
 +
 +imgname = '/images/icons/document.png'
 +
 +
 +Maintenant, nous pouvons essayer de charger les images dans les deux widgets Label que nous utilisons pour afficher les graphiques. Je dis « essayer » car je sais que si le programme est exécuté depuis /Bureau, il échouera. Nous piégerons cet échec et afficherons une boîte de message avec une erreur, juste pour être gentil (code montré page suivante, en haut à droite).
 +
 +Remarquez que je ne me suis pas soucié d'éventuelles erreurs avec « localpath »", puisqu'il s'agit d'un chemin entièrement qualifié et tant que :
 +••je saisis le nom de fichier correct du graphique et que
 +••le graphique existe, alors
 +il n'y aura pas de problème pour charger ce graphique. Je sais que je suis trop optimiste, mais c'est juste moi.
 +
  
 **The last thing I do is load the ScrolledText widget with the resulting outputs of each of the variables. We have to use the .insert() method, with the position that we want to add the text and then the data we want to insert. Since each line ends with a “\n”, and since the Text widget remembers the last place something was placed, it’s just an easy job to use the Tk.END (PAGE now imports the Tk.Constants module) to define the “where”, and the f-string formatted data as the “what”, and let Tkinter deal with the “how” (shown bottom left). **The last thing I do is load the ScrolledText widget with the resulting outputs of each of the variables. We have to use the .insert() method, with the position that we want to add the text and then the data we want to insert. Since each line ends with a “\n”, and since the Text widget remembers the last place something was placed, it’s just an easy job to use the Tk.END (PAGE now imports the Tk.Constants module) to define the “where”, and the f-string formatted data as the “what”, and let Tkinter deal with the “how” (shown bottom left).
  
 That’s it. So the bottom line is: if you are going to combine Tkinter and Graphics and Python, you probably should define the fully qualified path as the output from a call to os.path.dirname(os.path.abspath(__file__)) .** That’s it. So the bottom line is: if you are going to combine Tkinter and Graphics and Python, you probably should define the fully qualified path as the output from a call to os.path.dirname(os.path.abspath(__file__)) .**
 +
 +La dernière chose que je fais est de charger le widget ScrolledText avec les résultats de chacune des variables. Nous devons utiliser la méthode .insert(), avec la position à laquelle nous voulons ajouter le texte, puis les données que nous voulons insérer. Puisque chaque ligne se termine par « \n », et puisque le widget Text se souvient du dernier endroit où quelque chose a été placé, il est facile d'utiliser le module Tk.END (PAGE importe maintenant le module Tk.Constants) pour définir le « où », et les données formatées en f-string comme le « quoi », et laisser Tkinter s'occuper du « comment » (montré en bas à gauche).
 +
 +C'est tout. Au bout du compte : si vous allez combiner Tkinter et Graphics et Python, vous devriez probablement définir le chemin entièrement qualifié comme la sortie d'un appel à os.path.dirname(os.path.abspath(__file__)) .
 +
  
 **Quick Update **Quick Update
Ligne 88: Ligne 172:
  
     ImageDir = os.path.join(location, "images", "icons")**     ImageDir = os.path.join(location, "images", "icons")**
 +    
 +    
 +Mise à jour rapide
 +
 +J'ai fait une rapide mise au point pour montrer les résultats à l'utilisateur ainsi qu'à Don (l'auteur de PAGE). Don a répondu rapidement avec une correction sous la forme d'une nouvelle version alpha de PAGE pour que je puisse la tester. Le résultat de cette nouvelle coupe fournit encore une autre option pour les utilisateurs de PAGE (et peut être utilisé par d'autres programmeurs Python également). Dans PAGE, tout fichier graphique intégré inclus au moment de la conception est géré dans le fichier GUI. Son correctif ressemble à quelque chose comme ceci :
 + _script = sys.argv[0]
 +
 +_location = os.path.dirname(_script)
 +
 +Comme il s'agit d'une variable globale par défaut, la variable _location est disponible pour le reste du projet en tant que projectname._location. Cela simplifie la gestion des images dans le module _support. Si vous souhaitez créer une simple variable globale pour un chemin d'accès à une image dans votre projet, vous pouvez faire quelque chose comme ceci :
 +
 +    location = test1._location
 +
 +    global ImageDir
 +
 +    ImageDir = os.path.join(location, "images", "icons")
 +    
  
 **Then when you need to assign an image, you can use a simple definition anywhere within the project _support file. **Then when you need to assign an image, you can use a simple definition anywhere within the project _support file.
Ligne 102: Ligne 203:
  
 Until next time, as always; stay safe, healthy, positive and creative!** Until next time, as always; stay safe, healthy, positive and creative!**
 +
 +Ensuite, lorsque vous avez besoin d'assigner une image, vous pouvez utiliser une simple définition n'importe où dans le fichier _support du projet.
 +
 +mon_fichier = os.path.join(ImageDir, "dossier.png")
 +
 +Cela n'est pas limité aux PAGE ou aux images. Supposons que vous vouliez utiliser une base de données dans votre script Python. Vous devez faire pointer le programme vers le fichier de la base de données. En utilisant cette méthode, vous disposez d'un moyen rapide de définir le chemin d'accès à la base de données sans vous soucier de l'endroit d'où l'utilisateur exécute votre programme (l'image est présentée sur la page suivante, en haut à gauche).
 +
 +J'ai ajouté mon projet et mon code à mon dépôt github à https://github.com/gregwa1953/FCM-182-Python.
 +
 +Je promets que je vais VRAIMENT essayer de continuer la discussion sur les Styles et Thèmes de Tkinter le mois prochain !
 +
 +Jusqu'à la prochaine fois, comme toujours : restez en sécurité, en bonne santé, positif et créatif !
issue182/python.1656332213.txt.gz · Dernière modification : 2022/06/27 14:16 de d52fr