If there is one thing I find annoying about Python tutorials on the web, whether it be YouTube or just text based examples, is that they completely fail in the Show and Tell paradigm.
I was recently looking for tutorials on Glade. There are not many but the only one that is useful is by Terry Howald.
Basically, he explains what he wants to do and shows you how he did it.
I don’t want to watch someone tell me how to make a Button and then assign some useless task to it. I want a finished example that does something useful and tells me how to build it. Preferably with some code that I can Copy/Paste!!
So after writing some simple code for computing a Caesar Cypher, I decide that I wanted to use Tkinter to create a simple GUI to enter my data in a window and show the resultant cypher graphically.
And here is the example:
Now you know what it looks like and what it does, I can explain how I did it (or cobbled it together!) and make a tutorial on how it works.
First of all you need to have some kind of idea of what the app should look like when it’s finished. This may change as you build it, or indeed, will change as you build it. But you need a clear idea of the finished product at the start.
In this case I want the user to input a phrase, an integer number which will shift the alphabet in line with the Caesar Cypher rules and then show the output.
Secondly you need to have some sort of schema in mind of how this can be achieved. I will be using Tkinter in this example. It comes as standard with Python and has some good documentation and examples.
So my schema is fairly simple. I first want to create a class to call when i want the programme to run.
1 – Create a class with attributes and methods to construct my programme
2 – Set up the class to use Tkinter to create a window
3 – Add a tk.canvas to the window to store all the widgets I want to use
4 – Create a Frame and a text Entry to enter the phrase to code
5 – Do the same for the integer variable to use in the Caesar Cypher algorithm
6 – Create a Label to show the Cypher created by the algorithm
7 – Create a Button to generate the cypher and display it
8 – Create a button to clear the input data and start again
I also want to use a nice backdrop image to make it look good.
It’s always nice to write some information about your programme at the start:
''' Use a Class to rewrite the Ceaser Code in a Tkinter GUI Created 22-6-2019 Author - Finn McCool UTF8 Python 3.7.3 64-bit('base':conda)'''
This was written in VSCode with the anaconda package installed.
Install the packages we need. Tkinter of course and the Font package is installed to give us some better looking output.
import tkinter as tk from tkinter.font import Font
Add some Global variables to set the size of the window and the name of the Background image.
Now create the class which will do all the work for us:
class CaeserApp: def init(self):
The def init(self) statement is required. We can say that A = CaeserApp() and give A an instance of the class CaeserApp. This gives A access to all the attributes and methods of the class.
self.root = tk.Tk() self.root.title('Caeser Code') FONT = Font(family='Arial',size=12,weight='bold')
This instantiates a sub class from the Super class Tk(). That is, a window inheriting all the attributes and methods of the Super class. It is important to know that FONT can only be called after the root window has been made.
self.canvas = tk.Canvas(self.root,width=WIDTH,height=HEIGHT) self.canvas.pack() backdrop = tk.PhotoImage(file=img) backdrop_label = tk.Label(self.root,image=backdrop) backdrop_label.place(relwidth=1,relheight=1)
Next, create a Canvas object which can hold all our widgets.
‘self.canvas.pack’ uses the HEIGHT and WIDTH variables to fill the canvas to the dimensions required. The image file we want to use as a backdrop to the App is opened by using ‘tk.PhotoImage’ which creates an image which Tk can use.
Now create a Label widget, ‘backdrop_label’ using ‘tk.Label’ method which uses ‘self.root’ as it’s parent and use the methods ‘relwidth’ and ‘relheight’ to stuff the image into the Canvas filling all the available space up.
I have used the ‘.place’ method throughout this App. I found this easier than using the ‘.grid’ method to move objects around on the Canvas.
It uses offset measurements from X=0 and Y=0 from the top left of the Canvas to relatively place object. Other objects which are put into a Frame for example, can fill the frame space up by using the ‘relwidth and relative height set to 1. So to set up the Frame and text Entry objects we use:
message_frame = tk.Frame(self.root, bg='#33334d', bd=5) message_frame.place(relx=0.5, rely=0.1, relwidth=0.75, relheight=0.05, anchor='n') self.message_text = tk.Entry(message_frame, bg='#ffffff', font=FONT) self.message_text.place(relheight=1, relwidth=1)
Within the ‘message_frame’ we will place the ‘message_text’ which we want to encode. ‘message_frame inherits from ‘self.root’ (the main window) and we place it using the ‘.place’ method. ‘bg’ is the Hex number for the background. ‘anchor = ‘n” defines which direction the top most corner will be anchored at. Simply put, it is just like compass point. N, NE,E,SE,S,SW,W,NW and back to N for north. FONT is introduced here as the variable defined above.
We use similar code to place the frame to hold the variable to offset the letters in the alphabet to generate the Caesar Cypher.
offset_frame = tk.Frame(self.root, bg='#33334d', bd=5) offset_frame.place(relx=0.5, rely=0.75, relwidth=0.75, relheight=0.05, anchor='n') self.offset_text = tk.Entry(offset_frame, bg='#ffffff', font=FONT) self.offset_text.place(relheight=1, relwidth=0.25)
So now we can put a Button object in which will actually do something when it is clicked. The first button will be the CLEAR button which will clear all the user input.
clear_button = tk.Button(offset_frame, text='Clear', bg='grey', font=('Arial',11)) clear_button.place(relheight=1, relwidth=0.3, relx=0.35) clear_button.configure(command=self.clear_input)
The button is place into the previous ‘offset_frame’. The ‘clear_button.configure’ statement tells the App to run the function ‘clear_input’ which we will define a bit later.
Similarly, and using largely the same code, we place the button which does all the hard work generating the cypher. It is also placed in ‘offset_frame’ but this time runs the function ‘generate_code’.
generate_code_button = tk.Button(offset_frame, text="Generate", bg='grey', font=('Arial',11)) generate_code_button.place(relheight=1, relwidth=0.3, relx=0.7) generate_code_button.configure(command=self.generate_code)
Next a Frame and a Label are created to hold the output of the ‘generate_code’ function.
coded_frame = tk.Frame(self.root, bg='#33334d', bd=5) coded_frame.place(relx=0.5, rely=0.8, relwidth=0.75, relheight=0.1, anchor='n') self.cypher_text = tk.Label(coded_frame, bg='#ffffff', relief='raised', font=FONT, anchor='nw', justify='left', bd=5) self.cypher_text.place(relheight=1, relwidth=1,)
As you can see, much of the code is copy/paste and change some positions for the placement with a corresponding change of the object names.
The most important line is:
This actually shows the Main window and all the widgets. Without it. Nothing happens.
We have two working functions which are called when the ‘clear’ Button and the ‘generate_code’ buttons are clicked.
def clear_input(self): self.message_text.delete(0, 'end') self.offset_text.delete(0, 'end')
This clears the input text from the 1st letter to the last letter. It sets you up for another run.
The ‘generate_code function runs the Caeser Cypher code.
The ‘message’ and ‘key’ variables are instantiated by using the ‘self.message_text,get()’ and the int(self.offset_text,get()’ methods. Note that ‘key’ has to be set to an integer. The remaining code was explained in the last post.
def generate_code(self): message = str(self.message_text.get()) key = int(self.offset_text.get()) alphabet1 = ''.join(chr(x) for x in range(32, 127)) alphabet2 = alphabet1[key:]+alphabet1[:key] coded_message = '' for i in range(len(message)): x = alphabet1.find(message[i]) coded_message += (alphabet2[x]) self.cypher_text.config(text=coded_message)
To run the App, don’t forget to put:
Caeser = CaeserApp()
outside of the Class declaration.
And that is it. Show and Tell.
I hope you found this interesting and of course, feel free to add your own thoughts on how to make it better.
You can find all the code and images used on my Github page. Click Here!