开放的编程资料库

当前位置:我爱分享网 > Python教程 > 正文

Tkinter 教程 – 程序风格

过程式风格的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_screenwidthwinfo_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)

创建了一个Checkbuttonvariable参数设置关联变量。command参数确定在选择或取消选择Checkbutton时调用的函数。

图:TkinterCheckbutton

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方法使用绝对坐标将图像放置在窗口上。

图:TkinterLabelshowingimage

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方法被调用。

图:TkinterMessagebox

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菜单

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方法显示上下文菜单。弹出菜单显示在鼠标单击的xy坐标处。

图:Tkinter弹出菜单

Tkinter包布局管理器

pack几何管理器将小部件打包成行或列。我们可以使用fillexpandpadxpadyside等选项>控制布局。

#!/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添加了一些垂直空间。

图:Placinglabelsinarowwithpackmanager

在第二个示例中,我们将小部件放入一列。

#!/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

图:Placinglabelsinacolumnwithpackmanager

在第三个示例中,我们使用包管理器创建一行标签和一列标签。

#!/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)

使用columnconfigurerowconfigure方法,我们在行和列之间添加了一些空间。

btn1.grid(column=0, row=0)

grid方法将小部件放入网格中。columnrow属性指定单元格的索引。此按钮位于网格左上角的单元格中。

图:Tkinter网格管理器

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比例

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方法创建矩形。前四个参数是两个边界点的xy坐标:左上角和右下角点。通过outline参数,我们可以控制矩形轮廓的颜色。同样,fill参数为矩形内部提供颜色。

图:TkinterCanvascolours

在本教程中,我们使用过程式编程在Python中使用Tkinter创建了GUI应用程序。ZetCode上提供了一本独特的电子书Tkinter编程;PDF格式,包含200页和89个代码示例。

列出Python教程。

未经允许不得转载:我爱分享网 » Tkinter 教程 – 程序风格

感觉很棒!可以赞赏支持我哟~

赞(0) 打赏