We're going to make an app using python. To do this we need to import a library. We'll be using TKinter.
Line 1: import the tkinter library
Line 3: make a window (we're going to call it root which is common)
Line 5: ends the mainloop, so the computer knows to stop running code above this line
We can also change the title from tk to whatever we want, and set the dimensions of the window by doing these things:
Line 4: changes the title
Line 5: changes the shape to be 400 pixels wide, 300 tall.
You can also change the icon, but it must be an ico file and (for our learning) be saved in the same folder as our app.
Line 7: the file is in the same folder and it is a .ico file. The name has to be exact so in this case I called it icon.ico
You can make your own icon easily here: Favicon.io
Notice it changed it on our app. And in the screenshot below we see it was in the same folder as the .py program.
NOTE: If you're using an online IDE like replit then this will not work.
To add some readable text to the window we use labels. These are used to communicate with the user often to give instructions.
Line 9: makes the label and sets text to "Hello World!"
Line 10: adds it to the window
There's other things we can do to labels to modify them:
Line 9: declares the label
Line 10: sets text
Line 11: sets text colour
Line 12: sets background colour
Line 13: sets the width
Line 14: sets the height
Notice it's not a square, that's because it doesn't measure in pixels, it measures in character length/width which are generally taller.
What's the point of apps if not to push buttons?! Let's set up a program with a label and a button:
Line 8: declares and makes a button, sets the text to Click Me on it.
Line 11: packs in the button.
If you run this and click the button it does nothing. But we can program it to run a function so let's make it run a function that prints something in our console.
Line 3: made a function
Line 4: prints "Button has been clicked!!!" in the console each time it's clicked
Line 11: Button declared
Line 12: text is set to click me
Line 13: added a command, it runs the btnClicked function once this button is clicked.
Okay but printing to the console doesn't do anything in our app so let's update a label once it's clicked:
Line 4: change it to configure the label, it changes the label text on the button click
Sometimes we need to pass parameters to avoid excessive global variables. This way we can have a variable where someone types something in, or have a number display... Here's how to pass a variable into a command in a button:
Lines 4-5: a function that takes in an arguement and will set the label text to that parameter.
Line 10: Sets name to "Mr. Smith"
Line 14: uses lambda: updateLabel(name) to pass in the name variable into the words parameter which ultimately sets the text to Mr. Smith after you release your click.
One final note: buttons, like labels, can also have their height and width changed:
If we need to type in some data we'll need a text field
Line 10: made a textfield and called it entry, this will let the user type information in
Line 14: packs in the entry after the label but before the button.
Note: Order matters here!
Let's add a command and function to the button so that it can update the label to say hello to whoever types in their name:
Line 3: declares the btnClicked function
Line 4: sets the label text to Hello + (whatever is in the entry when the button is clicked)+!
Line 13: added a command to the button so it knows to run the function
Being able to use multiple choice instead of typing an answer is better in some situations. We unfortunately are getting larger and larger programs so I can only show you parts. This is how we declare radiobuttons:
Line 16-18: makes the radio buttons and sets their text.
Line 23-25: adds them to the app.
You may have noticed a problem in the app though, all the buttons are selected and not connected, to do this we need to give all these radio buttons a variable and a value to link them together. We can do so by modifying their declaration like this:
Line 9: we need to set up a tkinter string variable so the app will know the default value to start with. In this case we link it to the root window and set the default value to 1 so that we know which option is selected by default at the beginning.
Line 18: added variable=var, our tkinter string variable, then set this options value to 1. This will be our default option
Line 19: added variable=var, our tkinter string variable, then set this options value to 2.
Line 20: added variable=var, our tkinter string variable, then set this options value to 3.
Okay but we can see in our function it just says you selected something when you hit the submit button. To fix this we need to get the value of our tkinter string variable.
Line 4: updates our label to output You have selected (option number selected)
We know now that we can do lots in one window but what if we want to make a multipage app like a CYOA game or a Quiz? Well we can do that by making other windows, here's how to do it and add stuff to specific windows in Tkinter:
This is a pretty standard app, click the button and it prints in the console. Not super useful but it will help us moving forward.
Line 10: notice in the button I include the root property, that is which window this button will be in.
Let's change the function so that it makes a new window and adds a label and title to that window.
Line 4: makes a new window and automatically selects it
Line 5: changes the title to Next Window
Line 6: Changes the window dimensions
Line 7:Declares the label and links it to this window
Line 8: packs it into this window
Okay but it doesn't close the last window. In Tkinter if you close your root window it closes the whole program so let's add a button that closes the "Next Window"
Line 2: need to import the SUNKEN constant individually from the Tkinter library.
Line 10: makes a close button linked to windowOne, the command is to destroy windowOne, this will close it for us.
Line 12: adds it to windowOne so we can see it.
Okay but now we have an error where we can click the next window button on our original root window as many times as we want and fill up the screen. To fix this we can in the function configure that button to look pressed and disable it. This will allow it to be clicked only once.
Line 9: configures the next button to be sunken and disabled to stop infinite amounts of windows to be opened.
NOTE: if you want it to be a popup in the background set toplevel to TopLevel(root) on line 5.
Using multiple windows in Tkinter can be tricky but if you just make a few functions within functions you can get things going. Here's some sample code to get you started:
There are many different dialog boxes that do different things. I can't teach you about all of them but I can show you some useful ones. I'll encourage you to check out :
Line 8: makes a messagebox appear with the word Title in it's title of the window and the word Message in its message text.
We can change the icon and message by modifying line 8:
Line 8: Changed title to continue, message to "Error, do you want to continue?", and set the icon to error (the red x)
error, a red x
info, a blue i
warning, a yellow exclamation point
question, a blue question mark
There's also other message boxes that you can use, these change the icon and the answers you can give to different variations of yes/no/cancel. It could be useful: Python Messagebox documentation
What can we use these messageboxes for though if answering them does nothing? Well to understand how to use them we need to understand that most work like a function. If you select "yes" it will return true, if you select "no" or "cancel" it often returns false, and if you close it you get neither true or false (you need to store the result in a variable to use it). Note that we used askquestion and it always returns true regardless of if you select yes or no, so be careful of what you use. Here's how this looks in code:
Line 12: changes the messagebox to askyesno, this returns false if no is selected. put the message box in the if statement
Line 13: if the select yes it updates the label to "You selected to continue"
Line 14: else statement
Line 15: updates the label to "You did not select yes to continue"
So we can see how these message boxes can be used to access different things, you could even put functions inside the if statements to make new windows, count up a score, or do any number of things.
Okay at this point writing out tkinter each time you want to make something is becoming unbearable. To elminate this just use this:
Line 1: imports tkinter, no longer need to type tkinter before each widget or element.
Line 3: root is set as a tk window without "tkinter."
Line 4: btn is made without "tkinter." in front of button.
All the best apps have menu systems. You may have even seen some of them in your favorite programs and apps!
Line 1: import tkinter so we don't have to write tkinter. before each element
Line 3-6: made a function that makes a pop up window but doesn't set itself to the top level
Line 8: make out main window
Line 10: make the menubar and set it to root
Line 11: make the file menu, so this will be a menu within the menubar
Line 12: add the new label, it does the donothing function
Line13-16: repeats line 12
Line 18: adds a separator in the menu
Line 20: adds an exit label that will close the program
Line 21: adds the filemenu to the menubar as a cascading menu.
Line 23: configures the menu on root to be our menubar. This is the equivalent of packing it.
What if we want to add more menu items? Well here's how:
Essentially you're going to repeat the series of steps you did for the file menu. Granted you'll have to use other functions to make the menu do different things. For us we might just use this to restart the app, exit the app, and open a simple help screen.
You need to install the python image library (PIL for short). To do this first press the windows key, or start icon and type in "Powershell" without quotes. Select Windows Powershell and a terminal will pop up, don't be scared.
Next type in the command:
pip install pillow
Now you need to make sure you've selected the right interpreter on the school computers, you can skip this step if you're coding at home. this may change in the future as we update python on the computers. Your teacher may need to update their notes.
First, open up VS code to the project you're currently working on. This may be a new project. Press "Ctrl+Shift+P" to open a command prompt in VS code. Type "Python: Select Interpreter" without quotes.
Adding images is useful too! You have to have the images in the same folder as your code for this to work. I named mine "Smith.png"
Next, if you're on the school computer, select Python 3.10.5
Line 1: import tkinter so we don't have to type tkinter. before each element again
Line 2: import the pillow library so that we can use images
Line 4: makes the root window
Line 5: set up an image variable to be the image I have in my files
Line 6: set up a panel with the image variable inside
Line 7: pack the panel into the window
Line 8: end the program
You can also put images in buttons! An incredibly useful tool when making an idle clicker game...
Packing in widgets works okay but it can get very messy in larger projects. Luckily we have grid layouts to let us pack in widget more precisely.
Line 59: I set the button A to row 0, column 0, so the top left most spot. I padded the outside of it by 2 pixels so it doesn't touch anything else.
Line 60: I set the B button to the bottom left (row 1, column 0)
Line 61: I set the c button to the top right (row 0, column 1)
Line 62: I set the label to the bottom right (row 1, column 1)
With more elements you can place stuff in a larger grid. There's different modifiers that you can use on each element such as:
padx and pady: pads around the element
ipadx and ipady: pads inside the element (this will make buttons bigger)
columnspan and rowspan: sets the number of rows or columns that element can span. You may need to use some blank labels to get the span that you desire.
you can do a lot more with grid layout but click here for more:
Grid Layout Tutorial
What if you want to update your app, say once every second. Or once every 3 seconds... Or even delay updating the app after you click something.
There is a lot happening in this app, but it's necessary.
Lines 4-5: Sets the timer and increment to be 0 so that it will not count up yet.
Line 10: Start of the update function
Line 11: pulls in the increment and timer variables since they need to be changed and accessed.
Line 12: increases the timer by the value of increment, which is 0 for now until you start the timer. Then it will increase by 1.
Line 13: Updates the label to display the current time.
Line 14: root.after(1000, update) call the update function once every second (or 1000 ms = 1s)
Line 17: Start timer function, this function is to start the time.
Line 18: Pulls in increment because it needs to be set to 1 so the timer will start.
Line 19: Sets increment to 1, which means the timer will start.
Line 24: Button calls the start timer so it sets the increment to 1 so the timer will actually count up.
Line 30: Calls the update function as soon as the app is built so that it will keep calling itself once every second. This is necessary before the root.mainloop()
It may take a few readthroughs to understand what is happening. This will be invaluable.
root.after(1000) will delay the program by 1 second before continuing, you could also have it call a function
root.after(1000,function_name) which will then call said function. You could also use lambdas to pass parameters into the function call.