Error message here!

Hide Error message here!

忘记密码?

Error message here!

请输入正确邮箱

Hide Error message here!

密码丢失?请输入您的电子邮件地址。您将收到一个重设密码链接。

Error message here!

返回登录

Close

Python GUI Programming: introduction to Tkinter

TurboBoost 2021-04-21 11:54:21 阅读数:1 评论数:0 点赞数:0 收藏数:0

The content of this article comes from my notes . In the process of writing, I refer to Mr. Hu Junfeng 《Python Introduction to programming and data science 》 The content of the course .

This article contains a lot of code , Please run it to observe the effect while reading .

GUI Programming :Tkinter package

window

import tkinter as tk
import time
window = tk.Tk() # new window
window.title('Hello') # window title
window.geometry('350x200') # window size; can be changed by mouse dragging
print('press enter to show the window...')
input()
window.mainloop() # show window, start main loop.
# the main loop keeps monitoring the user's operations on the window, and make responses correspondingly.
print('window closed.')
press enter to show the window...
window closed.
# Please read first “ Common components ” and “ Layout plan ” Let's read this example again
import tkinter as tk
import time
window = tk.Tk()
window.title('Hello')
window.geometry('350x500')
def clicked1():
tk.Label(window, text='A clicked').pack()
window.update() # mainloop Will refresh every window from time to time , But I don't know the frequency . To be on the safe side, here's a manual refresh .
def clicked2():
new_window = tk.Tk()
new_window.geometry('200x150')
tk.Label(new_window, text='B clicked').pack()
# mainloop It's common to all windows . Now? mainloop Has been window Open the ,new_window There's no need to turn it on again , Just wait mainloop Just refresh yourself .
# If you don't want to wait , Run it new_window.update() It's fine too
new_window.after(1000, new_window.destroy) # Tell the new window , stay 1000ms And then close yourself .`after` Method will not block ; The new window remembers this and then turns around to do something else .
# `new_window.destroy()` The purpose of this is to close the window .( Similarly , Components also have destroy Method )
# It can't be used here time.sleep, Because in sleep In the process mainloop It will interrupt , In the meantime A There will be no response , There's no time for the new window to be displayed
button1 = tk.Button(window, text='A', font=('Courier New', 20), bg='blue', command=clicked1)
button1.pack()
button2 = tk.Button(window, text='B', font=('Courier New', 20), bg='red', command=clicked2)
button2.pack()
window.mainloop()
import tkinter as tk
import time
window = tk.Tk()
window.title('Hello')
window.geometry('350x500')
def my_update():
print('update!')
window.after(1000, my_update)
window.after(1000, my_update) # Refresh once per second
window.mainloop()

Common components

import tkinter as tk
window = tk.Tk()
window.title('Hello')
window.geometry('350x200')
label1 = tk.Label(window, text='L', font=('Courier New', 20), bg='grey', fg='blue') # a text label on `window`
label1.grid(column=0, row=0) # position the label at (0,0); the label won't show without this command
# the grid is dynamic; width of columns and height of rows is determined by the contents.
label2 = tk.Label(window, text='M', font=('Courier New', 20))
label2.grid(column=0, row=1)
label3 = tk.Label(window, text='G', font=('Courier New', 20))
label3.grid(column=1, row=0)
window.mainloop()
import tkinter as tk
window = tk.Tk()
window.title('Hello')
window.geometry('350x200')
def clicked():
button.configure(text='H', bg='white')
button = tk.Button(window, text='L', font=('Courier New', 20), bg='grey', fg='blue', command=clicked)
button.grid(column=0, row=0)
window.mainloop()
import tkinter as tk
from tkinter import messagebox
window = tk.Tk()
window.title('Hello')
window.geometry('350x200')
def clicked():
tk.messagebox.showinfo('Don\'t move', 'Raise your hands!', parent=window)
button = tk.Button(window, text='L', font=('Courier New', 20), bg='grey', fg='blue', command=clicked)
button.grid(column=0, row=0)
window.mainloop()
import tkinter as tk
window = tk.Tk()
window.title('Hello')
window.geometry('350x200')
label = tk.Label(window, text='[EMPTY]', font=('Courier New', 10))
label.grid(column=0, row=1)
txt = tk.Entry(window, width=10) # a one-line input box; width in px
txt.grid(column=0, row=0)
txt.focus() # put the focus on the input box as soon as the window gets focus;
# so that you don't need to click on the box and then start inputting.
def clicked():
label.configure(text=txt.get())
button = tk.Button(window, text='Submit', font=('Courier New', 10), bg='grey', fg='blue', command=clicked)
button.grid(column=1, row=0)
window.mainloop()
import tkinter as tk
from tkinter import ttk
window = tk.Tk()
window.title('Hello')
window.geometry('350x200')
label = tk.Label(window, text='[EMPTY]', font=('Courier New', 10))
label.grid(column=0, row=1)
combo = ttk.Combobox(window)
combo.grid(column=0, row=0)
combo['values'] = ('abc','de',123)
combo.current(1) # default is 'de'
def clicked():
label.configure(text=combo.get())
button = tk.Button(window, text='Submit', font=('Courier New', 10), bg='grey', fg='blue', command=clicked)
button.grid(column=1, row=0)
window.mainloop()

Other components include :

  • Checkbutton: Checkbox
  • Radiobutton: Radio buttons
  • ScrolledText: Multi-line text box
  • Spinbox: Numeric input box with up and down buttons
  • Progressbar: Progress bar
  • filedialog: “ Open file ” Dialog box

Layout plan

TKinter The nesting relationship between components in is tree like ( It's kind of like HTML Of tag), The window is the root of the tree , Non leaf nodes are often Frame Components —— A space occupying component that will not be displayed ( It's kind of like HTML Of span).

In every component , You can choose one of three layouts ( You can't use more than one ) To arrange his sons ( No grandson ):packgrid and place.

Pack programme

Pack The general idea of the plan is to simply stack the sons .

side Parameters
import tkinter as tk
window = tk.Tk()
window.title('Hello')
window.geometry('350x200')
label1 = tk.Label(window, text='L', font=('Courier New', 20), bg='grey', fg='blue') # a text label on `window`
label1.pack() # by default side='top'
label2 = tk.Label(window, text='M', font=('Courier New', 20))
label2.pack()
label3 = tk.Label(window, text='G', font=('Courier New', 20))
label3.pack()
window.mainloop()
import tkinter as tk
window = tk.Tk()
window.title('Hello')
window.geometry('350x200')
label1 = tk.Label(window, text='L', font=('Courier New', 20), bg='grey', fg='blue') # a text label on `window`
label1.pack(side='right')
label2 = tk.Label(window, text='M', font=('Courier New', 20))
label2.pack(side='right')
label3 = tk.Label(window, text='G', font=('Courier New', 20))
label3.pack(side='right')
window.mainloop()
import tkinter as tk
window = tk.Tk()
window.title('Hello')
window.geometry('350x200')
label1 = tk.Label(window, text='L', font=('Courier New', 20), bg='grey', fg='blue') # a text label on `window`
label1.pack(side='top')
label2 = tk.Label(window, text='M', font=('Courier New', 20))
label2.pack(side='bottom')
label3 = tk.Label(window, text='G', font=('Courier New', 20))
label3.pack(side='bottom')
window.mainloop()

As can be seen from the above examples ,pack() Will give priority to The top component in the code Of side Volunteer .

anchor Parameter and its relation with side The combination of
import tkinter as tk
window = tk.Tk()
window.title('Hello')
window.geometry('350x200')
label1 = tk.Label(window, text='L', font=('Courier New', 20), bg='grey', fg='blue') # a text label on `window`
label1.pack(anchor='nw') # northwest; similarly there're n,e,w,s,ne,se,sw,center
label2 = tk.Label(window, text='M', font=('Courier New', 20), bg='blue')
label2.pack(anchor='center')
label3 = tk.Label(window, text='G', font=('Courier New', 20), bg='red')
label3.pack(anchor='se')
window.mainloop()

Why are the three words not vertically distributed on 、 in 、 Next , It's the top half of the window ?

Because there's a default side=top, This makes every word in Be positioned to anchor The designated location after , And fall to the meeting . Take a look at the next two examples , You might know better .

import tkinter as tk
window = tk.Tk()
window.title('Hello')
window.geometry('350x200')
label1 = tk.Label(window, text='L', font=('Courier New', 20), bg='grey', fg='blue') # a text label on `window`
label1.pack(anchor='nw', side='bottom') # northwest; similarly there're n,e,w,s,ne,se,sw,center
label2 = tk.Label(window, text='M', font=('Courier New', 20), bg='blue')
label2.pack(anchor='center', side='bottom')
label3 = tk.Label(window, text='G', font=('Courier New', 20), bg='red')
label3.pack(anchor='se', side='bottom')
window.mainloop()
import tkinter as tk
window = tk.Tk()
window.title('Hello')
window.geometry('350x200')
label1 = tk.Label(window, text='L', font=('Courier New', 20), bg='grey', fg='blue') # a text label on `window`
label1.pack(anchor='n',side='right') # it starts at position `anchor` and then falls towards direction `side`
label2 = tk.Label(window, text='M', font=('Courier New', 20), bg='blue')
label2.pack(anchor='center',side='right')
label3 = tk.Label(window, text='G', font=('Courier New', 20), bg='red')
label3.pack(anchor='s',side='right')
window.mainloop()
fill and expand Parameters
import tkinter as tk
window = tk.Tk()
window.title('Hello')
window.geometry('350x200')
label1 = tk.Label(window, text='L', font=('Courier New', 20), bg='grey', fg='blue') # a text label on `window`
label1.pack(side='left',fill='y') # "fill=y" means that it will stretch vertically; but won't exceed the space assigned to it by pack
label2 = tk.Label(window, text='M', font=('Courier New', 20), bg='blue')
label2.pack(side='left',fill='y')
label3 = tk.Label(window, text='G', font=('Courier New', 20), bg='grey')
label3.pack(side='left',fill='y')
window.mainloop()
import tkinter as tk
window = tk.Tk()
window.title('Hello')
window.geometry('350x200')
label1 = tk.Label(window, text='L', font=('Courier New', 20), bg='grey', fg='blue') # a text label on `window`
label1.pack(side='top',fill='x') # stretch horizontally; won't exceed
label2 = tk.Label(window, text='M', font=('Courier New', 20), bg='blue')
label2.pack(side='top',fill='both') # stretch horizontally AND vertically; won't exceed; here it's no different from 'x'
label3 = tk.Label(window, text='G', font=('Courier New', 20), bg='grey')
label3.pack(side='top',fill='both')
window.mainloop()

As can be seen from the above examples , although fill Parameters make the component take up its allocated space , however pack Not because fill Parameter to allocate more space to a component .

Against it ,expand Parameters will require pack Allocate as much space as possible to one component . See the following example .

import tkinter as tk
window = tk.Tk()
window.title('Hello')
window.geometry('350x200')
label1 = tk.Label(window, text='L', font=('Courier New', 20), bg='grey', fg='blue') # a text label on `window`
label1.pack(side='top',fill='both',expand=True)
label2 = tk.Label(window, text='M', font=('Courier New', 20), bg='blue')
label2.pack(side='top',fill='both',expand=True)
label3 = tk.Label(window, text='G', font=('Courier New', 20), bg='grey')
label3.pack(side='top',fill='both',expand=True)
window.mainloop()
import tkinter as tk
window = tk.Tk()
window.title('Hello')
window.geometry('350x200')
label1 = tk.Label(window, text='L', font=('Courier New', 20), bg='grey', fg='blue') # a text label on `window`
label1.pack(side='top',fill='both',expand=True)
label2 = tk.Label(window, text='M', font=('Courier New', 20), bg='blue')
label2.pack(side='top',fill='both')
label3 = tk.Label(window, text='G', font=('Courier New', 20), bg='grey')
label3.pack(side='top',fill='both',expand=True)
window.mainloop()
import tkinter as tk
window = tk.Tk()
window.title('Hello')
window.geometry('350x200')
label1 = tk.Label(window, text='L', font=('Courier New', 20), bg='grey', fg='blue') # a text label on `window`
label1.pack(side='top',expand=True)
label2 = tk.Label(window, text='M', font=('Courier New', 20), bg='blue')
label2.pack(side='top',expand=True)
label3 = tk.Label(window, text='G', font=('Courier New', 20), bg='grey')
label3.pack(side='top',expand=True)
window.mainloop()

Grid programme

notes : When the parent component is not a window ( The root node ) when ,Grid A new grid will be drawn inside the parent component , Instead of using a full window grid .

notes : The height of different rows can be unequal ; Isomorphism .

import tkinter as tk
window = tk.Tk()
window.title('Hello')
window.geometry('350x200')
label1 = tk.Label(window, text='L', font=('Courier New', 20), bg='grey', fg='blue')
label1.grid(column=0, row=0)
label2 = tk.Label(window, text='M', font=('Courier New', 20), bg='blue')
label2.grid(column=0, row=1)
label3 = tk.Label(window, text='G', font=('Courier New', 20), bg='grey')
label3.grid(column=1, row=0, rowspan=2) # won't fill the entire 2x1 space
window.mainloop()
import tkinter as tk
window = tk.Tk()
window.title('Hello')
window.geometry('350x200')
label1 = tk.Label(window, text='L', font=('Courier New', 20), bg='grey', fg='blue')
label1.grid(column=0, row=0)
label2 = tk.Label(window, text='M', font=('Courier New', 20), bg='blue')
label2.grid(column=0, row=1, ipadx=5, ipady=10) # x_inner_padding=5, y_inner_padding=10
label3 = tk.Label(window, text='G', font=('Courier New', 20), bg='grey')
label3.grid(column=1, row=0, rowspan=2) # won't fill the entire 2x1 space
window.mainloop()
import tkinter as tk
window = tk.Tk()
window.title('Hello')
window.geometry('350x200')
label1 = tk.Label(window, text='L', font=('Courier New', 20), bg='grey', fg='blue')
label1.grid(column=0, row=0)
label2 = tk.Label(window, text='M', font=('Courier New', 20), bg='blue')
label2.grid(column=0, row=1, padx=5, pady=10) # x_outer_padding=5, y_outer_padding=10 ("margin" in css)
label3 = tk.Label(window, text='G', font=('Courier New', 20), bg='grey')
label3.grid(column=1, row=0, rowspan=2) # won't fill the entire 2x1 space
window.mainloop()

padx/pady/ipadx/ipady Parameter in Pack and Place Can also be used in .

import tkinter as tk
window = tk.Tk()
window.title('Hello')
window.geometry('350x200')
label1 = tk.Label(window, text='L', font=('Courier New', 20), bg='grey', fg='blue')
label1.grid(column=0, row=0)
label2 = tk.Label(window, text='M', font=('Courier New', 20), bg='blue')
label2.grid(column=0, row=1, padx=5, pady=10) # x_outer_padding=5, y_outer_padding=10 ("margin" in css)
label3 = tk.Label(window, text='G', font=('Courier New', 20), bg='grey')
label3.grid(column=1, row=0, rowspan=2, sticky='s') # `sticky` is similar to `anchor` in Pack (with the same list of possible values),
# but `sticky` determines the label's position **inside a cell**
window.mainloop()
import tkinter as tk
window = tk.Tk()
window.title('Hello')
window.geometry('350x200')
label1 = tk.Label(window, text='L', font=('Courier New', 20), bg='grey', fg='blue')
label1.grid(column=0, row=0)
label2 = tk.Label(window, text='M', font=('Courier New', 20), bg='blue')
label2.grid(column=0, row=1, padx=5, pady=10) # x_outer_padding=5, y_outer_padding=10 ("margin" in css)
label3 = tk.Label(window, text='G', font=('Courier New', 20), bg='grey')
label3.grid(column=1, row=0, rowspan=2, sticky='nsew') # same as `fill=both` in Pack. similarly, `sticky=ns` and `sticky=ew`.
window.mainloop()

Place programme

notes :Place The central coordinate system ( Including the parameters x,y It's in a coordinate system 、 and relx,rely It's in a coordinate system ) The origin of is always the upper left corner of the parent component , Instead of the upper left corner of the window ( If the parent component is not a window ).x And relx The only difference is the step size , It's not the origin of the coordinates .

import tkinter as tk
window = tk.Tk()
window.title('Hello')
window.geometry('350x200')
label1 = tk.Label(window, text='L', font=('Courier New', 20), bg='grey', fg='blue')
label1.place(x=100, y=50, width=50, height=100) # x in [0,width_of_father_in_px], y in [0,height_of_father_in_px]
label2 = tk.Label(window, text='M', font=('Courier New', 20), bg='blue')
label2.place(x=50, y=100, width=100, height=50)
window.mainloop()
import tkinter as tk
window = tk.Tk()
window.title('Hello')
window.geometry('350x200')
label1 = tk.Label(window, text='L', font=('Courier New', 20), bg='grey', fg='blue')
label1.place(relx=0.4, rely=0.2, relwidth=0.2, relheight=0.4) # relx in [0,1], rely in [0,1]
# relx=1 <=> x=width_of_father_in_px
label2 = tk.Label(window, text='M', font=('Courier New', 20), bg='blue')
label2.place(relx=0.2, rely=0.4, relwidth=0.4, relheight=0.2)
window.mainloop()

A combination of

import tkinter as tk
window = tk.Tk()
window.title('Hello')
window.geometry('350x200')
frame = tk.Frame(window, bg='black') # bg can be omitted (and it'll be transparent)
frame.place(x=50,y=50,width=100,height=100)
label1 = tk.Label(frame, text='L', font=('Courier New', 20), bg='grey', fg='blue') # a label whose father is `frame`
label1.pack(side='left')
label2 = tk.Label(frame, text='G', font=('Courier New', 20), bg='red')
label2.pack(anchor='se', side='right')
frame2 = tk.Frame(frame, bg='white')
frame2.pack(anchor='n', fill='both', expand=True)
label3 = tk.Label(frame2, text='M', font=('Courier New', 20), bg='blue')
label3.pack(fill='both', expand=True)
window.mainloop()
import tkinter as tk
window = tk.Tk()
window.title('Hello')
window.geometry('350x200')
frame0 = tk.Frame(window, bg='green')
frame0.pack(fill='both', expand=True)
frame = tk.Frame(window, bg='black') # bg can be omitted (and it'll be transparent)
frame.pack()
# the following code is the same as previous cell
label1 = tk.Label(frame, text='L', font=('Courier New', 20), bg='grey', fg='blue') # a label whose father is `frame`
label1.pack(side='left')
label2 = tk.Label(frame, text='G', font=('Courier New', 20), bg='red')
label2.pack(anchor='se', side='right')
frame2 = tk.Frame(frame, bg='white')
frame2.pack(anchor='n', fill='both', expand=True)
label3 = tk.Label(frame2, text='M', font=('Courier New', 20), bg='blue')
label3.pack(fill='both', expand=True)
window.mainloop()

As you can see from the example above , One frame Even by someone else (expand=True Of )frame Take up space , And at least there's room for future generations of components .

Event binding

Event binding , Let specific events trigger the execution of specific functions .Button Of command Parameters , Is a special case of event binding ; More generally, binding is done by the bind Method to complete .

import tkinter as tk
window = tk.Tk()
window.title('Hello')
window.geometry('350x200')
label1 = tk.Label(window, text='A', font=('Courier New', 20), bg='grey', fg='blue')
label1.pack()
label2 = tk.Label(window, text='U', font=('Courier New', 20))
label2.pack()
def enter(event):
print(event)
label1.configure(text='fuck')
def leave(event):
print(event)
label1.configure(text='A')
label2.bind('<Enter>', enter)
label2.bind('<Leave>', leave)
window.mainloop()
<Enter event focus=False x=21 y=0>
<Leave event focus=False x=19 y=-3>
<Enter event focus=False x=4 y=29>
<Leave event focus=False x=25 y=19>

For more information, see :

Copyright statement
In this paper,the author:[TurboBoost],Reprint please bring the original link, thank you

编程之旅,人生之路,不止于编程,还有诗和远方。
阅代码原理,看框架知识,学企业实践;
赏诗词,读日记,踏人生之路,观世界之行;