Ceci est une ancienne révision du document !
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.
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
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()
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)
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()
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).
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!