issue182:python
Différences
Ci-dessous, les différences entre deux révisions de la page.
Prochaine révision | Révision précédente | ||
issue182:python [2022/06/27 09:22] – créée auntiee | issue182: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, | + | **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, |
- | So what brought up this “issue”? | + | 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' |
- | 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 “/ | ||
- | Jumping back to the current | + | **So what brought up this “issue”? Well, the user was trying |
- | 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 | + | Alors, qu' |
- | The Tool | + | |
+ | **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 “/ | ||
+ | |||
+ | 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' | ||
+ | |||
+ | |||
+ | **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.** | ||
+ | |||
+ | Pour en revenir à la question actuelle, c' | ||
+ | |||
+ | 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' | ||
+ | |||
+ | |||
+ | **The Tool | ||
Since I was trying to create a GUI tool to easily point out the issue, of course I created a quick GUI in PAGE, not really trying to adhere to good GUI creation concepts. | Since I was trying to create a GUI tool to easily point out the issue, of course I created a quick GUI in PAGE, not really trying to adhere to good GUI creation concepts. | ||
Ligne 17: | Ligne 31: | ||
Of course, the GUI would need to provide a quick graphic representation showing either the success or failure of loading an image into a Tkinter widget as well as a quick indication of what each of the 6 different function calls returned, so I (or anyone else) could quickly decide on a solution. | Of course, the GUI would need to provide a quick graphic representation showing either the success or failure of loading an image into a Tkinter widget as well as a quick indication of what each of the 6 different function calls returned, so I (or anyone else) could quickly decide on a solution. | ||
- | 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, | + | 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, |
+ | |||
+ | L' | ||
+ | |||
+ | Puisque j' | ||
+ | |||
+ | 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' | ||
+ | |||
+ | Bien sûr, l' | ||
+ | |||
+ | Lorsqu' | ||
- | Three of the system calls ended up returning the same information, | + | **Three of the system calls ended up returning the same information, |
Here (previous page, top right) is a quick look and description of each. Honestly there are dozens more ways out there to do this, so if you want to try others, feel free. I’m just here to get the thought processes flowing. | Here (previous page, top right) is a quick look and description of each. Honestly there are dozens more ways out there to do this, so if you want to try others, feel free. I’m just here to get the thought processes flowing. | ||
Ligne 26: | Ligne 51: | ||
os.path.abspath(filename) | os.path.abspath(filename) | ||
+ | |||
+ | pathlib.Path().absolute() | ||
+ | |||
+ | os.path.abspath(os.getcwd())** | ||
+ | |||
+ | Trois des appels système ont fini par renvoyer les mêmes informations, | ||
+ | |||
+ | Voici (page précédente, | ||
+ | |||
+ | 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' | ||
+ | |||
+ | os.path.abspath(nom du fichier) | ||
pathlib.Path().absolute() | pathlib.Path().absolute() | ||
Ligne 31: | Ligne 68: | ||
os.path.abspath(os.getcwd()) | 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. | ||
Of the remaining three choices, any one of them returns the full path to our source folder, which is what we really want. We can always assign this to a variable for the path and append the path to our local image folder and the filename. | Of the remaining three choices, any one of them returns the full path to our source folder, which is what we really want. We can always assign this to a variable for the path and append the path to our local image folder and the filename. | ||
Ligne 39: | Ligne 77: | ||
Since this is a PAGE program and a very simple one at that, I decided to put all of the code in a function called “startup” which will get run just before the GUI is actually shown to the user. This includes trying to load both of the images as well as obtaining the path from the 6 system calls and loading a Text widget and the two dynamic text labels. The call to the startup function is the next-to-last line in the main function that PAGE provides. | Since this is a PAGE program and a very simple one at that, I decided to put all of the code in a function called “startup” which will get run just before the GUI is actually shown to the user. This includes trying to load both of the images as well as obtaining the path from the 6 system calls and loading a Text widget and the two dynamic text labels. The call to the startup function is the next-to-last line in the main function that PAGE provides. | ||
- | 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.** |
- | def startup(): | + | Cela signifie que, pour ce cas d' |
+ | |||
+ | Parmi les trois choix restants, chacun d' | ||
+ | |||
+ | Le code | ||
+ | |||
+ | Puisqu' | ||
+ | |||
+ | Bien sûr, nous devons importer les bibliothèques os et pathlib dans notre programme. | ||
+ | |||
+ | |||
+ | **def startup(): | ||
import os, pathlib | import os, pathlib | ||
Ligne 50: | Ligne 99: | ||
# Load the two labels with the paths | # Load the two labels with the paths | ||
+ | |||
+ | _w1.LocalPath.set(localpath) | ||
+ | |||
+ | _w1.ProperPath.set(abspath1)** | ||
+ | |||
+ | def startup(): | ||
+ | |||
+ | import os, pathlib | ||
+ | |||
+ | À ce stade, j' | ||
+ | |||
+ | Après avoir regardé les résultats lorsque je l'ai lancé depuis /Bureau, j'ai décidé d' | ||
+ | |||
+ | # Charger les deux étiquettes avec les chemins | ||
_w1.LocalPath.set(localpath) | _w1.LocalPath.set(localpath) | ||
Ligne 55: | Ligne 118: | ||
_w1.ProperPath.set(abspath1) | _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. | ||
# define the image name | # define the image name | ||
Ligne 67: | Ligne 131: | ||
• I type in the correct graphic filename and | • I type in the correct graphic filename and | ||
• 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.** |
- | 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” | + | A ce stade, je peux définir le nom de l' |
- | 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__)) . | + | # définir le nom de l' |
- | Quick Update | + | imgname = '/ |
+ | |||
+ | |||
+ | 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' | ||
+ | ••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”, | ||
+ | |||
+ | 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' | ||
+ | |||
+ | 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 | ||
I did a quick writeup to show the results to the user as well as Don (The author of PAGE). Don responded quickly with a fix in the form of a new alpha version of PAGE for me to test. The result of this new cut provides yet another option for PAGE users (and can be used by other Python programmers as well. In PAGE, any embedded graphics included at design time are handled in the GUI file. His fix looks something like this… | I did a quick writeup to show the results to the user as well as Don (The author of PAGE). Don responded quickly with a fix in the form of a new alpha version of PAGE for me to test. The result of this new cut provides yet another option for PAGE users (and can be used by other Python programmers as well. In PAGE, any embedded graphics included at design time are handled in the GUI file. His fix looks something like this… | ||
Ligne 82: | Ligne 166: | ||
Since this is a global variable by default, the _location variable is available to the rest of the project as projectname._location. This makes it simple to handle images within the _support module. If you wish to create a simple global for an image path in your project, you can do something like this… | Since this is a global variable by default, the _location variable is available to the rest of the project as projectname._location. This makes it simple to handle images within the _support module. If you wish to create a simple global for an image path in your project, you can do something like this… | ||
+ | |||
+ | location = test1._location | ||
+ | |||
+ | global ImageDir | ||
+ | |||
+ | ImageDir = os.path.join(location, | ||
+ | | ||
+ | | ||
+ | Mise à jour rapide | ||
+ | |||
+ | J'ai fait une rapide mise au point pour montrer les résultats à l' | ||
+ | | ||
+ | |||
+ | _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' | ||
location = test1._location | location = test1._location | ||
Ligne 88: | Ligne 188: | ||
ImageDir = os.path.join(location, | ImageDir = os.path.join(location, | ||
+ | | ||
- | 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. |
my_file = os.path.join(ImageDir, | my_file = os.path.join(ImageDir, | ||
Ligne 101: | Ligne 202: | ||
I promise I will REALLY try to continue the Tkinter Styles and Themes discussion next month! | I promise I will REALLY try to continue the Tkinter Styles and Themes discussion next month! | ||
- | 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' | ||
+ | |||
+ | mon_fichier = os.path.join(ImageDir, | ||
+ | |||
+ | 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' | ||
+ | |||
+ | J'ai ajouté mon projet et mon code à mon dépôt github à https:// | ||
+ | |||
+ | Je promets que je vais VRAIMENT essayer de continuer la discussion sur les Styles et Thèmes de Tkinter le mois prochain ! | ||
+ | |||
+ | Jusqu' |
issue182/python.1656314538.txt.gz · Dernière modification : 2022/06/27 09:22 de auntiee