Improving My Python Tkinter Code
sub-titled: “Well, that shouldn’t be too difficult!”

I fully admit that my coding overall, and especially my Tkinter code, should be a lot better after 9 months of self-learning.
A female can create a fully grown baby in that time, but I still struggle to write a well coded GUI. [That’s not meant as a sexist remark, but one of awe.]
Also, taking into account that I do a lot of Tk stuff in nearly every one of my projects, I really am quite ashamed of my code at times.
Git Hubbing
Yesterday I was browsing around GitHub looking for new and\or interesting code, when I found this small and beautifully written Tkinter tutorial. If you scroll to the end of the page you will see some code that produces several buttons with callbacks.
Interestingly, the code didn’t use lambdas for the callbacks, it used functools, now that in itself warranted further investigation as far as I was concerned.
Here is the original code from that tutorial:

I liked this, but why not use lambdas I wondered? The author explains that using lambda callbacks inside a loop can be confusing, as they all return the same value. That is certainly something to make a note of.
I could of left it there of course, and just noted how the loop worked, but as I am sure you know, unless you get involved and experiment with the code, it will usually soon be forgotten.
Shambolic Code
I wanted to make the code do a bit more, but still keep it very simple. I also wanted to code it in a way so that I would be able to understand it in the future, not so much Pythonic code as Shambolic code!
First of all I got rid of the ttk stuff, I couldn’t see the point in adding a layer of confusion for beginners, and the graphical effect was minimal to say the least in this tiny bit of code.
Imports Get Exported
For the imports I managed to cut that down to:
import functools as ft from tkinter import Tk, Frame, Button
That’s the first time I have ever used my own alias in an import. I saw in the original code that “command=functools.partial” was a bit long-winded and also, to a beginner may be a bit scary (still being a noob myself I understand these things, believe me, ha-ha.)
So I changed the original “import functools” to “import functools as ft“. All this means is that instead of having to type the word “functools”, you can just type “ft” instead.
So that command now became, “command=ft.partial“.
I also changed the import tkinter as this is frowned upon nowadays, and instead I just imported the exact modules the code needed, which were Tk, Frame and Button.
Pack To Grid
I tend to use grid instead of pack for 99% of my projects nowadays and in fact most Python experts recommend using grid as your default geometry manager.
But like the author argues in his tutorial, pack and place do have their uses in certain circumstances. I agree, but I decided to always use grid where possible in my future projects, so I just changed the pack.() parts to grid.().
however, I did lose the centering of the buttons by deleting the line “big_frame.pack(fill=’both’, expand=True)” and replacing it with grid.().
It does simplify things a bit more for beginners, and it’s not really a big deal being left justified, is it?
Variable Shortner
This is contentious, but to beginners long winded variable names can be really confusing. To that end I shortened several variable names, which in turn shortened the code, and in my eyes at least, it looks more readable and simple.
I also increased the amount of buttons for some reason, just greed I guess?
This is how the code looks now:

String Formatting
Next I needed to be certain that I understood those weird string formatting things, the %d, and % i.
This article on stack overflow did a good job of explaining it, so I see no point in re-iterating it again here, (pun intended).
We do not really have to understand what functools is doing under the hood, but there is no harm in reading up on it if you have the time. Pydanny has a great looking page on this subject called, Python Partials are Fun!
Experiment!
I wanted to make sure that I understood how to modify the button loop to insert more changes to the buttons. Note: Don’t forget this will work on other widgets too.
How about changing the colour of each button to an exact colour, eg. button one must be ‘salmon, button two ‘gray’ etc. The most obvious and easiest way I can think of is to use a list. Here are a list of colours that I want to apply to the buttons:
colors =["salmon","gray","green","yellow","orange","skyblue","white"]
Note: I have used the USA spelling of colours in the code as this seems to be the standard.
To change the background colour of a button we usually use, bg=”salmon” (or whatever colour), in the btn= line. To change that to be read in from a list is quite simple, just use this instead: bg=colors[i-1].
“colors” is the name of our list, the variable “i” the iterator, in other words the variable that is increased on each loop.
The variable i will start at 1, as defined in the Range starting parameter. If we started it with zero it was cause other complications, this is the simplest way, just reference colors -1.
Have a play about with the code to see what I mean.

If think we can agree this a is very simple, and even elegant, way of doing this, even though I coded some of it, so there’s a first, huh!
Fellow Newbs Tip
Here is my beginners tip for those that are confused with lists, tuples, dicts and sets, “just learn lists, the others will come naturally once you fully understand the basics of lists.”
Now we know how to add in other settings to the loop it shouldn’t be too hard to manipulate it however you want, but things can get complicated and that’s why I am ending this article here before I embarrass myself 
I hope to use this loop and functools in my next project that has a GUI with more than a few buttons. I may even go back over my old code and review how embarrassing it is and whether it is worth updating them.
'''
Button loop and ft callback
'''
import functools as ft
from tkinter import Tk, Frame, Button
root = Tk()
frame1 = Frame(root)
frame1.grid()
colors =["salmon","gray","green","yellow","orange","skyblue","white"]
def but_click (num):
print("You clicked button", num)
for i in range(1, 8):
btn = Button(frame1, bg=colors[i-1], text="Button %d" % i,
command=ft.partial(but_click, i))
btn.grid()
root.mainloop()
Using Python V3.6.5 32bit, on Windows 7 64bit
and Python V3.67 on Linux Mint 19.1 Cinnamon 64bit
Previous Post: Python Code Snippets 21
from Python Coder
via read more
No comments:
Post a Comment