过程式风格的Tkinter教程展示了如何使用过程式编程风格在Tkinter中创建简单的GUI应用程序。Tkinter教程中使用了面向对象的编程风格-OOP风格。
Tkinter
Tkinter是一个绑定到TkGUI工具包的Python。Tk是Tcl语言的原始GUI库。Tkinter是作为Python包装器实现的,它围绕着嵌入Python中的完整Tcl解释器。
Tkinter是Python标准安装的一部分。
Tkinter退出按钮
Button小部件是用于执行操作的标准Tkinter小部件。
#!/usr/bin/python
import tkinter
root = tkinter.Tk()
root.title('Quit button')
btn = tkinter.Button(root, text="Quit", width=8,
command=root.quit)
btn.pack(pady=10)
root.geometry("300x250+300+300")
root.mainloop()
该示例创建了一个退出按钮。单击按钮时,应用程序终止。
import tkinter
我们导入tkinter模块。
root = tkinter.Tk()
一个根窗口被创建。根窗口是我们应用程序中的主应用程序窗口。它有一个标题栏和边框。这些由窗口管理器提供。根窗口必须在任何其他小部件之前创建。
root.title('Quit button')
使用title方法,我们设置窗口的标题。
btn = tkinter.Button(root, text="Quit", width=8,
command=root.quit)
Button小部件已创建。按钮构造函数的第一个参数是父控件;它是根窗口。text参数指定按钮的标签。width设置按钮的宽度。command参数指定单击按钮时执行的函数。root.quit终止应用程序。
btn.pack(pady=10)
pack是Tkinter中的三个布局管理器之一。它将按钮放在父级上并显示它。pady在按钮上方和下方放置了一些空间。
root.geometry("300x250+300+300")
geometry方法设置窗口的大小并将其定位在屏幕上。前两个参数是窗口的宽度和高度。最后两个参数是x和y屏幕坐标。
root.mainloop()
最后,我们进入主循环。主循环从窗口系统接收事件并将它们分派给应用程序小部件。当我们点击标题栏的关闭按钮或调用quit方法时,它就终止了。
Tkinter中心窗口
通过geometry方法,我们将应用程序窗口置于屏幕中心。
#!/usr/bin/python
import tkinter
root = tkinter.Tk()
root.title('Centered window')
win_width = 300
win_height = 250
screen_width = root.winfo_screenwidth()
screen_height = root.winfo_screenheight()
start_x = int((screen_width/2) - (win_width/2))
start_y = int((screen_height/2) - (win_height/2))
root.geometry('{}x{}+{}+{}'.format(win_width, win_height,
start_x, start_y))
root.mainloop()
为了使窗口在屏幕上居中,我们需要知道屏幕和窗口的尺寸。
win_width = 300 win_height = 250
这是窗口的宽度和高度。
screen_width = root.winfo_screenwidth() screen_height = root.winfo_screenheight()
我们使用winfo_screenwidth和winfo_screenheight方法获取屏幕的宽度和高度。
start_x = int((screen_width/2) - (win_width/2)) start_y = int((screen_height/2) - (win_height/2))
我们计算窗口左上角的x和y坐标。
root.geometry('{}x{}+{}+{}'.format(win_width, win_height,
start_x, start_y))
我们用geometry将窗口放置在屏幕上。
Tkinter检查按钮
Checkbutton是一个有两种状态的小部件:打开和关闭。打开状态由复选标记可视化。
Checkbutton与变量关联。变量存储按钮的当前状态(打开或关闭)。
#!/usr/bin/python
import tkinter
def toggleTitle():
isTitleShown = cbvar.get()
if isTitleShown:
root.title('Checkbutton example')
else:
root.title('')
root = tkinter.Tk()
root.title('Checkbutton example')
cbvar = tkinter.BooleanVar()
cbtn = tkinter.Checkbutton(root, text="Show", width=8, variable=cbvar,
command=toggleTitle)
cbtn.select()
cbtn.pack(pady=10)
root.geometry("300x250+300+300")
root.mainloop()
Checkbutton位于窗口上。它显示或隐藏窗口的标题。
def toggleTitle():
isTitleShown = cbvar.get()
if isTitleShown:
root.title('Checkbutton example')
else:
root.title('')
toggleTitle函数切换窗口的标题。我们从关联的cbvar获取Checkbutton的状态。根据其状态,我们使用title显示或隐藏标题。
cbvar = tkinter.BooleanVar()
创建了一个BooleanVar。
cbtn = tkinter.Checkbutton(root, text="Show", width=8, variable=cbvar,
command=toggleTitle)
创建了一个Checkbutton。variable参数设置关联变量。command参数确定在选择或取消选择Checkbutton时调用的函数。
Tkinter标签
Label是一个可以显示文本或图像的标准小部件。
为了处理图像,我们需要安装pillow模块。
$ pip3 install pillow
我们使用pip安装模块。
#!/usr/bin/python
import tkinter
from PIL import Image, ImageTk
root = tkinter.Tk()
root.configure(background='gray')
root.title("Rotunda")
rot_i = Image.open("rotunda.jpg")
rotunda = ImageTk.PhotoImage(rot_i)
label = tkinter.Label(image=rotunda)
label.image = rotunda
label.place(x=20, y=20)
root.mainloop()
我们的示例显示JPG图像。
from PIL import Image, ImageTk
Label小部件只能显示一组有限的图像类型。要显示JPG图像,我们必须使用PIL,即Python图像库模块。通过Pillow教程了解有关PIL的更多信息。
root.configure(background='gray')
我们通过configure将主窗口的背景颜色更改为灰色。
rot_i = Image.open("rotunda.jpg")
我们从位于当前工作目录中的图像文件创建一个Image。
rotunda = ImageTk.PhotoImage(rot_i)
根据图像创建照片图像。
label = tkinter.Label(image=rotunda)
照片图像被赋予标签小部件的图像参数。
label.image = rotunda
必须存储图像引用,以免图像被垃圾收集。
label.place(x=20, y=20)
我们使用place方法使用绝对坐标将图像放置在窗口上。
Tkinter消息框
消息框是一个显示警告、错误或信息的小对话窗口。
#!/usr/bin/python
import tkinter
import tkinter.messagebox
import datetime
def showDate():
now = datetime.datetime.now()
msg = 'Today is: {}'.format(now)
tkinter.messagebox.showinfo("Information", msg)
root = tkinter.Tk()
root.title('Message box')
btn = tkinter.Button(root, text="Show date", padx=5, pady=5, width=10,
command=showDate)
btn.pack(pady=10)
root.geometry('300x300+300+250')
root.mainloop()
在这个例子中,我们展示了一个信息消息框。单击按钮时会显示该框。
import tkinter.messagebox
调用消息框的方法在tkinter.message模块中。
def showDate():
now = datetime.datetime.now()
msg = 'Today is: {}'.format(now)
tkinter.messagebox.showinfo("Information", msg)
showDate方法显示消息框。对话窗口显示当前日期和时间。tkinter.messagebox.showinfo显示信息消息框。
btn = tkinter.Button(root, text="Show date", padx=5, pady=5, width=10,
command=showDate)
点击按钮showDate方法被调用。
Tkinter菜单
菜单栏是位于各种菜单中的一组命令。我们可以在应用程序中使用的菜单组命令。
#!/usr/bin/python
import tkinter
import tkinter.messagebox
import datetime
def showDay():
now = datetime.datetime.now()
msg = 'Today is: {}'.format(now.strftime('%A'))
tkinter.messagebox.showinfo("Information", msg)
root = tkinter.Tk()
root.title('Menu')
menubar = tkinter.Menu(root)
root.config(menu=menubar)
fileMenu = tkinter.Menu(menubar)
fileMenu.add_command(label="Show day", command=showDay)
fileMenu.add_command(label="Exit", command=root.quit)
menubar.add_cascade(label="File", menu=fileMenu)
root.geometry('300x200+300+250')
root.mainloop()
该示例创建了一个包含两个选项的文件菜单:显示日期和退出。
def showDay():
now = datetime.datetime.now()
msg = 'Today is: {}'.format(now.strftime('%A'))
tkinter.messagebox.showinfo("Information", msg)
showDay显示一个显示当前日期的对话框。
menubar = tkinter.Menu(root) root.config(menu=menubar)
创建了一个菜单栏。它是一个常规的菜单小部件,配置为根窗口的菜单栏。
fileMenu = tkinter.Menu(menubar)
一个文件菜单对象被创建。菜单是包含命令的下拉窗口。
fileMenu.add_command(label="Show day", command=showDay) fileMenu.add_command(label="Exit", command=root.quit)
我们使用add_command方法添加两个选项。command属性指定在选择菜单选项时要调用的函数。
menubar.add_cascade(label="File", menu=fileMenu)
使用add_cascade方法,将文件菜单添加到菜单栏。
Tkinter弹出菜单
弹出菜单,也称为上下文菜单,是一种可以显示在窗口客户区任意位置的菜单。
#!/usr/bin/python
import tkinter
import tkinter.messagebox
import datetime
def showDay():
now = datetime.datetime.now()
msg = 'Today is: {}'.format(now.strftime('%A'))
tkinter.messagebox.showinfo("Information", msg)
def showMenu(e):
pmenu.post(e.x_root, e.y_root)
root = tkinter.Tk()
root.title('popup menu')
pmenu = tkinter.Menu(root, tearoff=0)
pmenu.add_command(label="Show day", command=showDay)
pmenu.add_command(label="Exit", command=root.quit)
root.bind("<Button-3>", showMenu)
root.geometry('300x250+300+250')
root.mainloop()
在示例中,我们创建了一个包含两个命令的弹出菜单。
pmenu = tkinter.Menu(root, tearoff=0)
上下文菜单是一个常规的菜单小部件。tearoff功能已关闭。现在无法将菜单分离到新的顶层窗口中。
root.bind("<Button-3>", showMenu)
我们将事件类型绑定到showMenu调用。当我们右键单击窗口的客户区时会生成该事件。
def showMenu(e):
pmenu.post(e.x_root, e.y_root)
showMenu方法显示上下文菜单。弹出菜单显示在鼠标单击的x和y坐标处。
Tkinter包布局管理器
pack几何管理器将小部件打包成行或列。我们可以使用fill、expand、padx、pady和side等选项>控制布局。
#!/usr/bin/python
import tkinter
root = tkinter.Tk()
root.title('Pack layout')
lbl1 = tkinter.Label(root, width=20, height=5, bg='SteelBlue2')
lbl1.pack(side=tkinter.LEFT, padx=10, pady=10)
lbl2 = tkinter.Label(root, width=20, height=5, bg='SteelBlue3')
lbl2.pack(side=tkinter.LEFT)
lbl3 = tkinter.Label(root, width=20, height=5, bg='SteelBlue4')
lbl3.pack(side=tkinter.LEFT, padx=10)
root.geometry('+300+250')
root.mainloop()
在这个例子中,我们将三个标签排成一行。
lbl1.pack(side=tkinter.LEFT, padx=10, pady=10)
使用side选项,我们将小部件打包成一行。padx添加了一些水平空间。pady添加了一些垂直空间。
在第二个示例中,我们将小部件放入一列。
#!/usr/bin/python
import tkinter
root = tkinter.Tk()
root.title('Pack layout')
lbl1 = tkinter.Label(root, width=20, height=5, bg='SlateGray2')
lbl1.pack(side=tkinter.TOP, pady=15, padx=10)
lbl2 = tkinter.Label(root, width=20, height=5, bg='SlateGray3')
lbl2.pack(side=tkinter.TOP, padx=10)
lbl3 = tkinter.Label(root, width=20, height=5, bg='SlateGray4')
lbl3.pack(side=tkinter.TOP, pady=15, padx=10)
root.geometry('+300+250')
root.mainloop()
该示例将三个标签放入一列。
lbl1.pack(side=tkinter.TOP, pady=15, padx=10)
为了将标签放入列中,我们将side选项设置为tkinter.TOP。
在第三个示例中,我们使用包管理器创建一行标签和一列标签。
#!/usr/bin/python
import tkinter
root = tkinter.Tk()
root.title('Pack layout')
frame1 = tkinter.LabelFrame(root, text='Vertical layout',
relief=tkinter.GROOVE)
lbl1 = tkinter.Label(frame1, width=15, height=3, bg='SlateGray2')
lbl1.pack(side=tkinter.TOP, pady=15, padx=10)
lbl2 = tkinter.Label(frame1, width=15, height=3, bg='SlateGray3')
lbl2.pack(side=tkinter.TOP, padx=10)
lbl3 = tkinter.Label(frame1, width=15, height=3, bg='SlateGray4')
lbl3.pack(side=tkinter.TOP, pady=15, padx=10)
frame1.pack(pady=10)
frame2 = tkinter.LabelFrame(root, text='Horizontal layout',
relief=tkinter.GROOVE)
lbl4 = tkinter.Label(frame2, width=15, height=3, bg='SkyBlue2')
lbl4.pack(side=tkinter.LEFT, pady=15, padx=10)
lbl5 = tkinter.Label(frame2, width=15, height=3, bg='SkyBlue3')
lbl5.pack(side=tkinter.LEFT, padx=10)
lbl6 = tkinter.Label(frame2, width=15, height=3, bg='SkyBlue4')
lbl6.pack(side=tkinter.LEFT, pady=15, padx=10)
frame2.pack(padx=10, pady=10)
root.geometry('+300+250')
root.mainloop()
我们创建了两个LabelFrame小部件。这些将包含标签。框架本身被打包成一列。
frame1 = tkinter.LabelFrame(root, text='Vertical layout',
relief=tkinter.GROOVE)
lbl1 = tkinter.Label(frame1, width=15, height=3, bg='SlateGray2')
lbl1.pack(side=tkinter.TOP, pady=15, padx=10)
lbl2 = tkinter.Label(frame1, width=15, height=3, bg='SlateGray3')
lbl2.pack(side=tkinter.TOP, padx=10)
lbl3 = tkinter.Label(frame1, width=15, height=3, bg='SlateGray4')
lbl3.pack(side=tkinter.TOP, pady=15, padx=10)
frame1.pack(pady=10)
第一个LabelFrame包含一列三个标签。
frame2 = tkinter.LabelFrame(root, text='Horizontal layout',
relief=tkinter.GROOVE)
lbl4 = tkinter.Label(frame2, width=15, height=3, bg='SkyBlue2')
lbl4.pack(side=tkinter.LEFT, pady=15, padx=10)
lbl5 = tkinter.Label(frame2, width=15, height=3, bg='SkyBlue3')
lbl5.pack(side=tkinter.LEFT, padx=10)
lbl6 = tkinter.Label(frame2, width=15, height=3, bg='SkyBlue4')
lbl6.pack(side=tkinter.LEFT, pady=15, padx=10)
frame2.pack(padx=10, pady=10)
第二个LabelFrame包含一行三个标签。
Tkinter网格布局管理器
网格布局管理器在二维网格中组织其子项。网格由列和行组成。列和行的交叉点称为单元格。
#!/usr/bin/python
import tkinter
root = tkinter.Tk()
root.title('Grid')
root.columnconfigure(0, pad=5)
root.columnconfigure(1, pad=5)
root.columnconfigure(2, pad=5)
root.rowconfigure(0, pad=5)
btn1 = tkinter.Button(root, text='Button 1')
btn1.grid(column=0, row=0)
btn2 = tkinter.Button(root, text='Button 2')
btn2.grid(column=1, row=0)
btn3 = tkinter.Button(root, text='Button 3')
btn3.grid(column=2, row=0)
btn4 = tkinter.Button(root, text='Button 4')
btn4.grid(column=0, row=1)
btn5 = tkinter.Button(root, text='Button 5')
btn5.grid(column=1, row=1)
btn6 = tkinter.Button(root, text='Button 6')
btn6.grid(column=2, row=1)
root.geometry('300x300+300+250')
root.mainloop()
在示例中,我们将六个按钮放置在一个网格中。
root.columnconfigure(0, pad=5) root.columnconfigure(1, pad=5) root.columnconfigure(2, pad=5) root.rowconfigure(0, pad=5)
使用columnconfigure和rowconfigure方法,我们在行和列之间添加了一些空间。
btn1.grid(column=0, row=0)
grid方法将小部件放入网格中。column和row属性指定单元格的索引。此按钮位于网格左上角的单元格中。
Tkinter比例
“比例”小部件允许用户通过沿比例移动旋钮来选择数值。我们可以控制最小值和最大值以及分辨率。
#!/usr/bin/python
import tkinter
def onScale(val):
v = int(val)
lvar.set(v)
root = tkinter.Tk()
root.title('Scale example')
root.columnconfigure(0, pad=5)
root.columnconfigure(1, pad=15)
root.rowconfigure(0, pad=5)
scale = tkinter.Scale(root, from_=0, to=100, orient=tkinter.HORIZONTAL,
command=onScale)
scale.grid(column=0, row=0)
lvar = tkinter.IntVar()
label = tkinter.Label(root, text=0, textvariable=lvar)
label.grid(column=1, row=0)
root.geometry("300x220+300+300")
root.mainloop()
在代码示例中,我们有一个Scale和一个Label。使用Scale选择的值显示在相邻的Label中。布局是使用网格管理器创建的。
def onScale(val):
v = int(val)
lvar.set(v)
onScale方法在我们移动Scale的旋钮时被调用。我们获取刻度的当前值并将其设置为标签的关联变量。
scale = tkinter.Scale(root, from_=0, to=100, orient=tkinter.HORIZONTAL,
command=onScale)
Scale小部件已创建。我们指定初始值和结束值、方向和回调函数。
lvar = tkinter.IntVar() label = tkinter.Label(root, text=0, textvariable=lvar)
这是显示比例尺选定值的标签。
Tkinter按键事件
当用户按下键盘键时会产生按键事件。我们使用bind方法将事件类型映射到事件处理程序。按键事件的事件类型是。
#!/usr/bin/python
import tkinter
def onKeyPress(e):
msg = 'Key {}, (code {}) was pressed'.format(e.keysym, e.keycode)
lvar.set(msg)
root = tkinter.Tk()
root.title('Key event')
lvar = tkinter.StringVar()
lbl = tkinter.Label(root, text="coordinates", textvariable=lvar)
lbl.place(x=20, y=20)
root.bind('<Key>', onKeyPress)
root.geometry("300x250+300+300")
root.mainloop()
在示例中,我们在标签小部件中显示了按下键的键事件属性。
def onKeyPress(e):
msg = 'Key {}, (code {}) was pressed'.format(e.keysym, e.keycode)
lvar.set(msg)
onKeyPress是按键事件的事件处理程序。我们在标签小部件中显示按键符号和按键代码。
root.bind('<Key>', onKeyPress)
我们将事件类型绑定到onKeyPress事件处理程序。
Tkinter鼠标移动事件
鼠标移动事件的事件类型是。
#!/usr/bin/python
import tkinter
def onMotion(e):
msg = 'x: {} y: {}'.format(e.x, e.y)
lvar.set(msg)
root = tkinter.Tk()
root.title('Mouse move event')
lvar = tkinter.StringVar()
lbl = tkinter.Label(root, text="coordinates", textvariable=lvar)
lbl.place(x=20, y=20)
root.bind('<Motion>', onMotion)
root.geometry("300x250+300+300")
root.mainloop()
该示例显示了当前鼠标指针在labelwidget中的坐标。
def onMotion(e):
msg = 'x: {} y: {}'.format(e.x, e.y)
lvar.set(msg)
在onMotion回调中,我们获取鼠标指针的x和y坐标,形成一条文本消息并将其设置为标签的关联变量。
root.bind('<Motion>', onMotion)
我们将事件类型绑定到onMotion回调。
Tkinter跳转按钮
以下示例是一个使用事件类型的小型预告片应用程序。enter事件在用户使用鼠标指针进入小部件时生成。
#!/usr/bin/python
import tkinter
import random
def onEnterButton(e):
w = root.winfo_width()
h = root.winfo_height()
b_w = btn.winfo_width()
b_h = btn.winfo_height()
r_x = random.randrange(0, w - b_w)
r_y = random.randrange(0, h - b_h)
btn.place(x=r_x, y=r_y)
root = tkinter.Tk()
root.title('Jumping button')
root.resizable(False, False)
btn = tkinter.Button(root, text='Exit', width=10, command=root.quit)
btn.place(x=180, y=20)
btn.bind('<Enter>', onEnterButton)
root.geometry("600x600+30+30")
root.mainloop()
用户试图点击按钮,这应该会终止应用程序。按钮通过从鼠标指针处随机跳转来逃避点击。
def onEnterButton(e):
w = root.winfo_width()
h = root.winfo_height()
b_w = btn.winfo_width()
b_h = btn.winfo_height()
r_x = random.randrange(0, w - b_w)
r_y = random.randrange(0, h - b_h)
btn.place(x=r_x, y=r_y)
onEnterButton函数在用户进入按钮区域时被调用。我们确定根窗口和按钮的尺寸。然后我们使用这些值在窗口区域随机重新定位按钮。按钮通过使用绝对坐标的place方法显示。
root.resizable(False, False)
我们不允许窗口调整大小,这让用户更难接受。
btn = tkinter.Button(root, text='Exit', width=10, command=root.quit)
按钮的command属性设置为root的quit方法。如果用户设法单击按钮,则窗口终止。
btn.bind('<Enter>', onEnterButton)
我们将事件类型绑定到onEnterButton回调。
Tkinter画布颜色
Tkinter中的绘图是在Canvas小部件上完成的。Canvas是在Tkinter中进行图形处理的高级工具。
#!/usr/bin/python
import tkinter
root = tkinter.Tk()
root.title('Canvas colours')
canvas = tkinter.Canvas(root)
canvas.create_rectangle(30, 10, 120, 80,
outline="#fb0", fill="#fb0")
canvas.create_rectangle(150, 10, 240, 80,
outline="#f50", fill="#f50")
canvas.create_rectangle(270, 10, 370, 80,
outline="#05f", fill="#05f")
canvas.pack(fill=tkinter.BOTH, expand=1)
root.geometry("400x100+300+300")
root.mainloop()
该示例显示了三个填充了三种不同颜色的矩形。
canvas = tkinter.Canvas(root)
创建了Canvas小部件。
canvas.create_rectangle(30, 10, 120, 80,
outline="#fb0", fill="#fb0")
使用create_rectangle方法创建矩形。前四个参数是两个边界点的x和y坐标:左上角和右下角点。通过outline参数,我们可以控制矩形轮廓的颜色。同样,fill参数为矩形内部提供颜色。
在本教程中,我们使用过程式编程在Python中使用Tkinter创建了GUI应用程序。ZetCode上提供了一本独特的电子书Tkinter编程;PDF格式,包含200页和89个代码示例。
列出Python教程。
