copy/paste

23 Ağustos 2019 Cuma

Designing a simple GUI with Python (tkinter)

Python is one of the major languages are used for the development of both desktop and web applications. Python has features that take care of common programming tasks. Python is simple to learn and easy to use. Sometimes, python marks as slower than other widely used programming languages like Java. Python applications can speed up by simply maintaining the code and using custom runtime

Python does support the modules and packages, which encourages program modularity and code reuse. Python provides an increase in productivity, which makes the first choice of developers. It has a great learning curve as it supports functional and procedural programming language. It is open source and can be freely distributed. The programming language mainly selected based on the requirement and compatibility with platforms and database.

For More: https://www.educba.com/uses-of-python/

As we advance through the AI era, Python is mostly the choice of programmers. Python lends itself better to future advancements, it is highly prefered by beginner programmers to start their career.
In this post, I will try to show how to use tkinter to create a basic GUI.

We start by importing the necessary modules.

First we import everything from tkinter module:

from tkinter import *

(For python2, use Tkinter)

This is the only import we really need to have. Now we can create our main screen:

root = Tk()
root.mainloop()


By using Tk() initialization, we initialize our main screen.
mainloop() function will assure that the program is running. It HAS to be at the end of your code, any changes made in your main screen should be written between these two lines.

Your frame should look like this:



To change the name displayed on the window, we can use the following code:

root.winfo_toplevel().title("MY PROGRAM")

Now, we resize and relocate our window. To make code more readable, it is better to use variables.

width = 300
height = 300
pos_x = 250
pos_y = 400

This will make our window located in (250,400) of our screen, with the size of 300x300:

root.geometry('%dx%d+%d+%d' % (width, height, pos_x, pos_y))

If you want to locate the window in the middle of the screen, you can use this instead:

pos_x = root.winfo_screenwidth()
pos_y= root.winfo_screenheight()
root.geometry('%dx%d+%d+%d' % (width, height, (pos_x / 2) - (width / 2), (pos_y / 2) - (height / 2)))

Our code so far:

from tkinter import *

root = Tk()
root.winfo_toplevel().title("MY PROGRAM")
width = 300
height = 300
pos_x = 250
pos_y = 400
root.geometry('%dx%d+%d+%d' % (width, height, pos_x, pos_y))
root.mainloop()

Program should look like this:


Let's add a background to our program. Download and move this image to the same folder where your program is.


To use this image for background, we will use PhotoImage class.

We define a variable named "img" and make sure that it belongs to our root.

img = PhotoImage(master = root, file="background.png")

Now, we create a label to hold our image. Labels are display boxes, where you can show off your images or texts.

lab = Label(root, compound=CENTER, image=img)

And finally, we put the label into our main frame.

lab.place(x=0, y=0, relwidth=1, relheight=1)

The code should look like this:

img = PhotoImage(master = root, file="background.png")
lab = Label(root, compound=CENTER, image=img)
lab.place(x=0, y=0, relwidth=1, relheight=1)

And program:


So far so good. Now, let's add some buttons.

To create button, we should firstly create a function, which will be executed after user presses it.
Let's create a button that will show the current time, when pressed.
To show pop-up messages and get the time, we need to import some more modules:

from tkinter import messagebox
from datetime import datetime

Now, we will create our function to show pop-up messages to user:

def show_time():
messagebox.showinfo("Time", "Current time is: " + str(datetime.now()))

Create a button:

time_button = Button(root, text="Time", command=show_time)
time_button.pack()

text variable of button is the text you want to display on the button.
While declaring your command, don't use () at the end of your function. Else, while Python interpretes your code, it will execute it immediately.
pack() function will make your button ready for your frame. HOWEVER, packing your buttons and labels will make your GUI to place them one by one downwards.
pack() is the simplest way to make your frame show your buttons. If you want to place your button to a specific location, use place() instead:

time_button.place(x=25, y=30)

This will place your button to (25,30)

Now, let's add a text that tells us what does this button do. To do this, we need to create a new label:

text_label = Label(root, text="show time", font=("Courier", 11), fg="Yellow", bg="Black")

fg is the color our label text is, and bg is the background color of our label.
Now, place this label next to our button:

text_label.place(x=85, y=30)

So far, our code looks like this:

from tkinter import *
from tkinter import messagebox
from datetime import datetime


def show_time():
messagebox.showinfo("Time", "Current time is: " + str(datetime.now()))


root = Tk()
root.winfo_toplevel().title("MY PROGRAM")
width = 300
height = 300
pos_x = 250
pos_y = 400
root.geometry('%dx%d+%d+%d' % (width, height, pos_x, pos_y))
img = PhotoImage(master = root, file="background.png")
lab = Label(root, compound=CENTER, image=img)
lab.place(x=0, y=0, relwidth=1, relheight=1)
time_button = Button(root, text="Time", command=show_time)
time_button.place(x=25, y=30)
text_label = Label(root, text="show time", font=("Courier", 11), fg="Yellow", bg="Black")
text_label.place(x=85, y=30)
root.mainloop()

And program:


What if we want to keep time updated, in our main screen?
First we will create a new time label:

time_label = Label(root, font=("Courier", 11), fg="Yellow", bg="Black")
time_label.place(x=30,y=245)

However, we need to keep this label updated every second, so we will create a refresher, that will keep our main frame updated.
We create a new function named update:

def update():
time_label.configure(text="Time: " + str(datetime.now())[:19])
root.after(250, update)

This will refresh main screen every 250ms.
We will simply call this function in somewhere between initialization and mainloop().

Code so far:

from tkinter import *
from tkinter import messagebox
from datetime import datetime


def show_time():
messagebox.showinfo("Time", "Current time is: " + str(datetime.now()))


def update():
time_label.configure(text="Time: " + str(datetime.now())[:19])
root.after(250, update)


root = Tk()
root.winfo_toplevel().title("MY PROGRAM")
width = 300
height = 300
pos_x = 250
pos_y = 400
root.geometry('%dx%d+%d+%d' % (width, height, pos_x, pos_y))
img = PhotoImage(master = root, file="background.png")
lab = Label(root, compound=CENTER, image=img)
lab.place(x=0, y=0, relwidth=1, relheight=1)
time_button = Button(root, text="Time", command=show_time)
time_button.place(x=25, y=30)
text_label = Label(root, text="show time", font=("Courier", 11), fg="Yellow", bg="Black")
text_label.place(x=85, y=30)
time_label = Label(root, font=("Courier", 11), fg="Yellow", bg="Black")
time_label.place(x=30,y=245)
update()
root.mainloop()

Looks like:


Now, let's create our second button. It will terminate our program. Firstly, create its function:

def exit():
root.quit()

This function will basically terminate the program. What if the user clicked it by mistake? Then we need to add an extra check:

def exit():
if messagebox.askokcancel("Quit!", "Do you want to exit?") == 1:
root.quit()

This will ask user if they want to exit. askokcancel() returns an integer, 1 if clicked OK. If user clicks so, then the program will terminate. Rest is creating the button:

exit_button = Button(root, text="Quit", command=exit)
exit_button.place(x=75,y=160)

Sometimes, it might be necessary to ask user for an input. Let's ask for users name and greet them in our time label!
We define a name variable and show it in our time label, so we modify our update method:

name = ""
def update():
time_label.configure(text="Hello " + name + "!\n" + "Time: " + str(datetime.now())[:19])
root.after(250, update)

Let's create a function that will ask for user's name. But first, we need an additional import:

from tkinter import simpledialog

Now our function:

def get_name():
global name
name = simpledialog.askstring("Name", "What is your name?")

And creating the required button:

name_button = Button(root, text="Enter name", command=get_name)
name_button.place(x=75,y=185)

Our code will be like following:

from tkinter import *
from tkinter import messagebox
from datetime import datetime
from tkinter import simpledialog


def get_name():
global name
name = simpledialog.askstring("Name", "What is your name?")


def show_time():
messagebox.showinfo("Time", "Current time is: " + str(datetime.now()))


name = ""
def update():
time_label.configure(text="Hello " + name + "!\n" + "Time: " + str(datetime.now())[:19])
root.after(250, update)


def exit():
if messagebox.askokcancel("Quit!", "Do you want to exit?") == 1:
root.quit()


root = Tk()
root.winfo_toplevel().title("MY PROGRAM")
width = 300
height = 300
pos_x = 250
pos_y = 400
root.geometry('%dx%d+%d+%d' % (width, height, pos_x, pos_y))
img = PhotoImage(master = root, file="background.png")
lab = Label(root, compound=CENTER, image=img)
lab.place(x=0, y=0, relwidth=1, relheight=1)
time_button = Button(root, text="Time", command=show_time)
time_button.place(x=25, y=30)
text_label = Label(root, text="show time", font=("Courier", 11), fg="Yellow", bg="Black")
text_label.place(x=85, y=30)
time_label = Label(root, font=("Courier", 11), fg="Yellow", bg="Black")
time_label.place(x=30,y=245)
exit_button = Button(root, text="Quit", command=exit)
exit_button.place(x=75,y=160)
name_button = Button(root, text="Enter name", command=get_name)
name_button.place(x=75,y=185)
update()
root.mainloop()

And will look like:


While asking string, if the user cancels the operation, then the assigned variable will be None. You will get the following error if you press cancel while being asked for a string:

TypeError: can only concatenate str (not "NoneType") to str

That is because name became None and Python can't convert it to str in our update method. A basic checker will fix it. Just update the screen depending on a condition:

def update():
if name is not None and name is not "":
time_label.configure(text="Hello " + name + "!\n" + "Time: " + str(datetime.now())[:19])
else:
time_label.configure(text="Time: " + str(datetime.now())[:19])
root.after(250, update)

It won't try to show name from now if it is not entered.

These are the basics of creating a simple GUI in python. If you have any question, if you get any error, feel free to ask me!
This is the final code:

from tkinter import *
from tkinter import messagebox
from datetime import datetime
from tkinter import simpledialog


def get_name():
global name
name = simpledialog.askstring("Name", "What is your name?")


def show_time():
messagebox.showinfo("Time", "Current time is: " + str(datetime.now()))


name = ""
def update():
if name is not None and name is not "":
time_label.configure(text="Hello " + name + "!\n" + "Time: " + str(datetime.now())[:19])
else:
time_label.configure(text="Time: " + str(datetime.now())[:19])
root.after(250, update)


def exit():
if messagebox.askokcancel("Quit!", "Do you want to exit?") == 1:
root.quit()


root = Tk()
root.winfo_toplevel().title("MY PROGRAM")
width = 300
height = 300
pos_x = 250
pos_y = 400
root.geometry('%dx%d+%d+%d' % (width, height, pos_x, pos_y))
img = PhotoImage(master = root, file="background.png")
lab = Label(root, compound=CENTER, image=img)
lab.place(x=0, y=0, relwidth=1, relheight=1)
time_button = Button(root, text="Time", command=show_time)
time_button.place(x=25, y=30)
text_label = Label(root, text="show time", font=("Courier", 11), fg="Yellow", bg="Black")
text_label.place(x=85, y=30)
time_label = Label(root, font=("Courier", 11), fg="Yellow", bg="Black")
time_label.place(x=30,y=245)
exit_button = Button(root, text="Quit", command=exit)
exit_button.place(x=75,y=160)
name_button = Button(root, text="Enter name", command=get_name)
name_button.place(x=75,y=185)
update()
root.mainloop()