Now we've seen how a typical GUI program is structured, let's try a more advanced example.
It will be based on the File Walk App we created earlier, which searched the file system, using the os.walk function to obtain a list of files and sub-directories.
Open another new file in Geany, save it as 'tk-search.py' and type in the code below:
1 |
# A GUI search program using tkinter |
While there are quite a few lines of code here, I hope you can pick out the function definitions and typical GUI app structure.
We've still have our tkinter module import on line 4, while line 5 imports the os module. You'll also notice the init function and another event callback function, this time called search. More on these later.
More Widgets
On line 40 we create the top-level window object. This time we need quite a few widgets. These are created on lines 42 to 49.
The labels and entry boxes will provide our user input interface. The label text is set using the text configuration parameter. The two entry fields will hold the starting directory and file ending strings, and have a display width assignment of twelve characters.
On line 47 a listbox widget is created. This will hold a list of matched files. Specifying a width of 80 characters will cater for any long path names. A search might find many files. So, we need a vertically oriented scrollbar. We'll 'attach' this scrollbar to the listbox later.
And finally, on line 49, we create a button widget to kick off the search operation. The three parameters specify the button label text, the callback function name, and a width of eight characters.
Lines 52 and 53 call the init function and start the main window loop, just like we saw in the Basic GUI App post.
Using Grid Layout
Now back to the init function. With more widgets it's quite a bit longer than before, and there's also something new to learn. Our widgets need to be positioned in particular locations. Luckily, the Tkinter module has a built-in grid layout feature.
You can think of a grid layout as a collection of empty boxes or cells, organised into rows and columns - very like the cells in a spreadsheet. The cells are numbered from the top left corner starting from zero. A widget is placed in a particular grid cell with the widget's grid function.
We start on line 11 with the cell at column zero row zero, which will contain the starting directory label widget. On line 12 we populate the cell in column zero row one with the starting directory entry widget. Lines 13 and 14 repeat this process for the file ending's label and entry widgets for rows three and four. On line 15 we add the search button to row five in column zero.
By now I'm sure you noticed the sticky configuration parameter on the labels. The 'W' setting means 'West' and ensures the label text will line up on the left hand side of the column.
The second column, column one, only contains the listbox widget. However, the rowspan configuration parameter will stretch it to fill five rows - matching the number or rows we assigned in column zero.
The final column has the scrollbar. This is also stretched over five rows and has a 'NorthSouth' stickiness to ensure it fills the full column space. We 'attach' the scrollbar to the listbox using the statements on lines 19 and 20. This will ensure the listbox contents scroll when the scrollbar is moved.
The last two lines of the function, 21 and 22, set default text string values for the entry widgets.
The Search Callback
Now for the search function. Remember this is called when the search button is clicked, as per the callback setting on line 49. The first two lines, 27 and 28, extract the contents of the entry widgets and store them in two string variables, startDir and fileEnding.
Line 31 deletes all the items in the listbox, to remove any files from a previous search.
Our search is done in lines 34 to 37. Line 34 starts a loop and calls the os.walk function with our startDir string. This function returns a list of paths, files and sub-directories. Line 35 is another loop which extracts each file in the file list, and stores it in the fileName variable.
The conditional if statement on line 36 compares the end of the fileName string with our entered fileEnding. If the test is True then it adds a new string to the listbox, using the path and file name.
And that's it. Run the program using Geany's Build->Execute menu option, or F5
key.
Experiment by trying different file endings and starting directories.
Make It Your Own
As we've seen a GUI program requires quite a bit more code than a simple terminal-based one. However, the flexibility offered by a widget-based user interface is certainly worth the effort.
GUI programming is a big subject. In this short article we've barely scratched the surface. The possibilities for refinement are almost endless. For example, you could change a widget's size or colour, add new widgets, or create a completely different layout.
Python 2.7
Remember, for Python 2.7 you'll need to install Tkinter. If you see a message that says 'No module named Tkinter' then take a look at my previous Installing Tkinter post.
A post from my Learn Python on the Raspberry Pi tutorial.