**Greetings again, fellow Beings. I hope your October (and November so far) has been happy. This month, I will take a look at the TkinterMapView library. You can find it at https://github.com/TomSchimansky/TkinterMapView As I usually do, I used PAGE 7.6 (the current release) to throw together a GUI for the demo. Besides the fact that I’m too lazy to make the demo directly in Tkinter, this shows how easy it is to create a map viewer within PAGE without having to use a custom widget. Below is an image that shows the demo in the PAGE designer. You can see how simple the GUI is to put together. While all of the widgets I used to create the demo are ttk widgets (with the exception of the ScrolledListbox), you can easily change that to use standard Tk widgets. There is nothing special about the widget set. As you can see, there are only two Frames, two Labels, six Buttons, one TEntry and the ScrolledListbox, so if you decide to forgo the use of PAGE for Tkinter, it won’t take you too much coding to recreate it. The only things I “hard coded” in PAGE are the widget alias for the buttons, the button callback names and the text variable for the TEntry widget.** Je vous salue à nouveau, chers amis. J'espère que votre mois d'octobre (et novembre jusqu'à présent) a été heureux. Ce mois-ci, je vais me pencher sur la bibliothèque TkinterMapView. Vous la trouverez à l'adresse suivante : https://github.com/TomSchimansky/TkinterMapView Comme je le fais habituellement, j'ai utilisé PAGE 7.6 (la version actuelle) pour créer une interface graphique pour la démo. Outre le fait que je suis trop paresseux pour faire la démo directement dans Tkinter, cela montre à quel point il est facile de créer une visionneuse de cartes dans PAGE sans avoir à utiliser un widget personnalisé. Vous trouverez ci-dessous une image qui montre la démo dans l'outil de création de PAGE. Vous pouvez voir à quel point l'interface graphique est simple à mettre en place. Bien que tous les widgets que j'ai utilisés pour créer la démo soient des widgets Ttk (à l'exception de la ScrolledListbox), vous pouvez facilement les modifier pour utiliser des widgets Tk standard. Il n'y a rien de spécial à propos du jeu de widgets. Comme vous pouvez le voir, il n'y a que deux cadres, deux étiquettes, six boutons, un TEntry et la ScrolledListbox ; donc si vous décidez de renoncer à l'utilisation de PAGE pour Tkinter, il ne vous faudra pas trop de codage pour le recréer. Les seules choses que j'ai « codées en dur » dans PAGE sont l'alias du widget pour les boutons, les noms des fonctions de rappel des boutons et la variable texte pour le widget TEntry. **Once I had my GUI designed, I saved the PAGE project, and generated the GUI and Support Python modules. Before you start coding your demo, you will need to install the library, using pip (or pip3): pip3 install tkintermapview Now that you have your system ready for the project, let’s look at the support module. Remember, PAGE creates skeletons of all the callbacks and the base code for showing the Tkinter program. First, we need to start with the imports. As I usually do, I’ll show the entire code for the functions, but when it comes to the PAGE function skeleton code, I’ll put the code you would need to add in bold and the rest of the code in “normal” face. In reality, the only line that needs to be here is the import sys line, but I created and call a small function that runs at startup to show some information about the system the program is running on, which is often helpful for debugging purposes. So you don’t need the last two lines in this section unless you will be using the “show_environ_info” function. import sys import platform import os** Une fois mon interface graphique conçue, j'ai sauvegardé le projet PAGE et généré les modules Python d'interface graphique et de support. Avant de commencer à coder votre démo, vous devrez installer la bibliothèque en utilisant pip (ou pip3) : pip3 install tkintermapview Maintenant que votre système est prêt pour le projet, regardons le module de support. Rappelez-vous, PAGE crée des squelettes de toutes les fonctions de rappel et le code de base pour afficher le programme Tkinter. Tout d'abord, nous devons commencer par les importations. Comme je le fais habituellement, je montrerai le code complet des fonctions, mais lorsqu'il s'agit du code du squelette de la fonction PAGE, je mettrai le code que vous devriez ajouter en gras et le reste du code en caractères « normaux ». En réalité, la seule ligne qui doit se trouver ici est la ligne import sys, mais j'ai créé et appelé une petite fonction qui s'exécute au démarrage pour montrer quelques informations sur le système sur lequel le programme s'exécute, ce qui est souvent utile à des fins de débogage. Vous n'avez donc pas besoin des deux dernières lignes de cette section, à moins que vous n'utilisiez la fonction « show_environ_info ». import sys import platform import os **Now for the Tkinter code. The only thing to be added to the support module is the import for the message box. Now for the Tkinter code. The only thing to be added to the support module is the import for the message box. import tkinter as tk import tkinter.ttk as ttk from tkinter.constants import * import tkinter.messagebox as messagebox Next to last, we need to import the tkintermapview library. Since the program won’t run at all without this library, I add the try|except catch to provide information to the user that the library isn’t installed. try: from tkintermapview import TkinterMapView except: msg = "You must install tkintermapview using pip." print(msg) sys.exit()** Passons maintenant au code Tkinter. La seule chose à ajouter au module de support est l'importation de la boîte de message. import tkinter as tk import tkinter.ttk as ttk from tkinter.constants import * import tkinter.messagebox as messagebox En avant-dernier, nous devons importer la bibliothèque tkintermapview. Comme le programme ne fonctionnera pas du tout sans cette bibliothèque, j'ajoute le piège try|except pour informer l'utilisateur que la bibliothèque n'est pas installée. try : // d52fr : cette ligne est une commande // from tkintermapview import TkinterMapView except : msg = "Vous devez installer tkintermapview à l'aide de pip." print(msg) sys.exit() **Finally, the GUI.py file is imported so our GUI definitions are loaded. import tkintermapviewdemo Top right is the main function, which again, PAGE creates for us. The only thing that needs to be added is a call to the startup function, which provides initialization code for the program. The startup function (below) is not part of the PAGE provided skeleton sets, so everything is added. First we set a few globals, create an empty list called markerList, define the default zoom level for the map, and insert the TkinterMapView widget into the second TFrame. Make sure you include the .place(x=0,y=0) line so the widget completely fills the TFrame. Next, we provide a starting location for the Map widget. I decided to use one of my favorite spots in the world, Garden of the Gods in Colorado. This returns a pointer to the location object. I set the marker option to True. Then tell the map widget to use the defaultZoomLevel, and add the marker pointer to the markerList list and create a variable named cntr for the item number in the List box. search_marker = map_widget.set_address("Garden of the Gods, Co", marker=True) map_widget.set_zoom(defaultZoomLevel) markerList.append(search_marker) cntr = len(markerList)** Enfin, le fichier GUI.py est importé pour que les définitions de l'interface graphique soient chargées : import tkintermapviewdemo En haut à droite se trouve la fonction main, que PAGE crée pour nous. La seule chose à ajouter est un appel à la fonction startup, qui fournit le code d'initialisation du programme. La fonction startup (ci-dessous) ne fait pas partie du squelette fourni par PAGE, donc tout est ajouté. Tout d'abord, nous définissons quelques valeurs globales, créons une liste vide appelée markerList, définissons le niveau de zoom par défaut pour la carte et insérons le widget TkinterMapView dans la deuxième TFrame. Assurez-vous d'inclure la ligne .place(x=0,y=0) pour que le widget remplisse complètement la TFrame. Ensuite, nous fournissons un emplacement de départ pour le widget Map. J'ai décidé d'utiliser l'un de mes endroits préférés au monde, le Jardin des Dieux dans le Colorado. Cette commande renvoie un pointeur vers l'objet location. J'ai mis l'option marqueur à True. J'indique ensuite au widget map d'utiliser le niveau de zoom par défaut, j'ajoute le pointeur du marqueur à la liste markerList et je crée une variable nommée cntr pour le numéro de l'élément dans la boîte List : search_marker = map_widget.set_address("Garden of the Gods, Co", marker=True) map_widget.set_zoom(defaultZoomLevel) markerList.append(search_marker) cntr = len(markerList) **I then add the text to the Entry widget, insert the text (with the counter number) into the ScrolledListbox. Then I call the set_bindings function to deal with the bindings needed, show the environment debugging information. Next I disable the CreateMarker button, since it was for future development, set the title bar, and center the Toplevel widget in the user’s screen (next page, top right). With the startup function finished, we can now look at some of the other functions that I use to support the program. This (next page, bottom right) is the show_environ_info function. It basically shows some generic system information in the terminal when the program gets run. The set_bindings function (next page, top left) does what the title says. It sets the bindings for the Entry widget and the ScrolledlListbox. Here is the keypress callback for the Entry widget, which will call the on_btnGo function when the user hits the Enter key. def on_entryKeyPress(e): if e.keysym == "Return": on_btnGo()** J'ajoute ensuite le texte au widget Entry, puis j'insère le texte (avec le numéro du compteur) dans la ScrolledListbox. J'appelle ensuite la fonction set_bindings pour traiter les liaisons nécessaires et afficher les informations de débogage de l'environnement. Ensuite, je désactive le bouton CreateMarker, puisqu'il est destiné à un développement futur, je place la barre de titre et je centre le widget Toplevel dans l'écran de l'utilisateur (page suivante, en haut à droite). La fonction de démarrage étant terminée, nous pouvons maintenant examiner certaines des autres fonctions que j'utilise pour soutenir le programme. Voici (page suivante, en bas à droite) la fonction show_environ_info. Elle affiche des informations génériques sur le système dans le terminal lorsque le programme est lancé. La fonction set_bindings (page suivante, en haut à gauche) fait ce que son titre indique. Elle définit les bindings pour le widget Entry et la Scrolled1Listbox. Voici la fonction de rappel keypress pour le widget Entry, qui appellera la fonction on_btnGo lorsque l'utilisateur appuiera sur la touche Entrée : def on_entryKeyPress(e) : si e.keysym == "Return" : on_btnGo() **Since the Map widget supports right-clicking on the map to get the Latitude and Longitude of the click point, I’ve included the ability of right-clicking in the Entry widget to allow the pasting from the clipboard (bottom left). When the user clicks on an item in the ScrolledListbox, this code set will “recall” the location from the listbox and cause the map widget to recentre the map location (bottom right). Now it’s time to fill in the code for all of the callback functions for our buttons. Remember, PAGE creates the skeleton functions, so only the code that you need to add will be in bold. The ClearMarkers callback will go through the marker list and use the map_widget.delete() method, then all the markers in the ScrolledListbox will be deleted. Notice this delete ALL markers (next page, top right). The ClearPath callback simply calls the mapwidget.delete_all_path method to remove the entire path from the map (next page, bottom right). The CreatePath callback walks through the list of markers and calls the map_widget.set_path method. It draws a line on the map between the markers (next page, bottom left).** Comme le widget Map permet de cliquer avec le bouton droit de la souris sur la carte pour obtenir la latitude et la longitude du point de clic, j'ai inclus la possibilité de cliquer avec le bouton droit de la souris dans le widget Entry pour permettre le collage à partir du presse-papier (en bas à gauche). Lorsque l'utilisateur clique sur un élément de ScrolledListbox, ce jeu de code « rappelle » l'emplacement dans la liste et fait en sorte que le widget de la carte recentre l'emplacement de la carte (en bas à droite). Il est maintenant temps de compléter le code de toutes les fonctions de rappel de nos boutons. Rappelez-vous que PAGE crée les fonctions squelettes, donc seul le code que vous devez ajouter sera en gras. La fonction ClearMarkers va parcourir la liste des marqueurs et utiliser la méthode map_widget.delete(), puis tous les marqueurs de la ScrolledListbox seront supprimés. Remarquez que cette méthode supprime TOUS les marqueurs (page suivante, en haut à droite). Le callback ClearPath appelle simplement la méthode mapwidget.delete_all_path pour supprimer l'intégralité du chemin de la carte (page suivante, en bas à droite). Le callback CreatePath parcourt la liste des marqueurs et appelle la méthode map_widget.set_path. Elle dessine une ligne sur la carte entre les marqueurs (page suivante, en bas à gauche). **The btnGo callback gets the address (or coordinates) from the Entry widget then calls the map.widget.set_address method to create a place on the map. We automatically call the method with the marker=True parameter to make sure there is a marker on the map. The return from the method is checked to see if the get address search was successful. If so, the marker is added. If not, an error message box will be shown to the user (next page). That’s it. The program should now run and allow you to show maps, markers and paths. The TkinterMapView widget provides MUCH MUCH more functionality than I’ve explored here. I strongly suggest you visit Tom’s GitHub repository and download the code so you can get more documentation and his example programs. I’ve created a repository on GitHub for the code for this project. You can find it at https://github.com/gregwa1953/FCM-199 Until next time, as always; stay safe, healthy, positive and creative!** Le callback btnGo obtient l'adresse (ou les coordonnées) du widget Entry, puis appelle la méthode map.widget.set_address pour créer un lieu sur la carte. Nous appelons automatiquement la méthode avec le paramètre marker=True pour nous assurer qu'il existe un marqueur sur la carte. Le retour de la méthode est vérifié pour voir si la recherche d'adresse a réussi. Si c'est le cas, le marqueur est ajouté. Dans le cas contraire, un message d'erreur est affiché (page suivante). Le tour est joué. Le programme devrait maintenant fonctionner et vous permettre d'afficher des cartes, des marqueurs et des chemins. Le widget TkinterMapView offre BEAUCOUP plus de fonctionnalités que celles que j'ai explorées ici. Je vous suggère fortement de visiter le dépôt GitHub de Tom et de télécharger le code afin d'obtenir plus de documentation et ses programmes d'exemple. J'ai créé un dépôt sur GitHub pour le code de ce projet. Vous pouvez le trouver à l'adresse suivante : https://github.com/gregwa1953/FCM-199 Jusqu'à la prochaine fois, comme toujours, restez en sécurité, en bonne santé, positifs et créatifs ! // Traduction de la ligne noire de l'encart en bas à droite page 19 // **This final function simply centres the project in the user’s screen.** Cette dernière fonction centre le projet dans l'écran de l'utilisateur. // Traduction de la ligne noire de l'encart en bas à gauche page 20 // **The btnExit callback simply calls sys.exit() to end the program.** La fonction de rappel btnExit appelle simplement sys.exit() pour terminer le programme.