【Python应用】tkinter简介

简介

tkinter是Python自带的GUI库。

tkinter的全称是Tk Interface。

其中Tk是开发桌面应用的GUI工具库,它是Tcl的标准GUI,而Tcl全称Tool Command Language,是一种动态编程语言,可用于桌面应用开发。关于Tk和Tcl,可以在https://www.tcl.tk/查看到更多的内容,这里不多做介绍。

Tk和Tcl并不是Python的一部分,Python只不过提供了与Tk和Tcl交互的接口,而Tk和Tcl是系统本身支持的,Window、Linux和MacOS都是支持的,所以通过Python tkinter创建的GUI程序可以在不同的操作系统使用。

一个简单的示例

通过如下命令可以将tkinter导入到Python:

import tkinter

之后就可以使用了,以下是一个最简单的例子:

import tkinter

if __name__ == '__main__':
    root = tkinter.Tk()
    root.mainloop()

通过Tk()就创建了一个窗口组件,mainloop()表示开始渲染这个窗口。执行该脚本得到的应用:

【Python应用】tkinter简介_第1张图片

这其实只是一个什么也没有的框体。为了能够使其有用,还需要在这个窗口组件之上增加额外的组件,来完成需要的功能。这个将在后面详细介绍。

组件介绍

首先对上面的代码做如下的修改:

import tkinter
import tkinter.ttk as ttk

class application(tkinter.Frame):
    pass

if __name__ == '__main__':
    root = tkinter.Tk()
    app  = application(master=root)
    root.title("Config Editor")
    root.geometry("1200x800")
    root.mainloop()

这里创建了一个类application,它的参数是窗口组件,这样在类的初始化过程中就可以同时初始化窗口组件,增加各类组件,完成需要实现的功能。这里的类并不是必要的,之所以要创建一个类,而不是直接在上述代码中实现,是因为最终窗口是有特定的功能需要实现的,通过类的方式来包装能够更好地实现功能。

title()函数为窗口组件增加名称,会在窗口头部显示(下图红色部分);而geometry()函数设置了窗口的尺寸,也方便后续增加内容。其执行结果如下:

【Python应用】tkinter简介_第2张图片

后续的内容就是在类application中增加各类组件。

Frame

Frame表示的是一个框架组件,在屏幕上显示为一个矩形区域,多用来作为容器。

它的创建也很简单(事实上所有的组件创建都很简单):

fram = tkinter.Frame(root, bg='red', height=30, width=130)

这里通过Frame类创建框架实例,参数说明如下:

  • root表示父组件,通常所有的组件都有一个父组件,而最常用的父组件就是tkinter.Tk()
  • 之后的参数,比如bgheightwidth,都是可选的,它们规定了框架的属性,比如颜色、高度、长度等,所有Frame支持的属性如下所示:
可选项 描述
bg 框架背景颜色。
bd 框架的宽度,默认为2个像素。
cursor 1、鼠标移动到框架时,光标的形状;
2、可以设置为arrowcirclecrossplus 等。
height 框架的高度,默认值是 0。
highlightbackground 框架没有获得焦点时,高亮边框的颜色,默认由系统指定。
highlightcolor 框架获得焦点时,高亮边框的颜色。
highlightthickness 指定高亮边框的宽度,默认值为0不带高亮边框。
relief 1、边框样式;
2、可选的有:FLATSUNKENRAISEDGROOVERIDGE
3、默认为FLAT
width 设置框架宽度,默认值是0。
takefocus 指定该组件是否接受输入焦点(用户可以通过Tab键将焦点转移上来),默认为false

Frame创建之后并不会直接显示,而是需要通过pack()来布局和显示:

fram.pack(side=tkinter.TOP, anchor=tkinter.SE)

实际上除了使用pack()来进行布局,还有其它的方法,这里说明:

  • pack():按添加顺序排列组件。
  • grid():按行列形式排列组件。
  • place():能够实现自定义排列组件。

这里只说明pack()的实现。

pack()接受一系列的位置参数,说明如下:

可选项 描述
anchor 1、控制组件在pack()分配的空间中的位置;
2、"n""ne""e""se""s""sw""w""nw""center"来定位;
3、默认值是"center"
expand 1、指定是否填充父组件的额外空间;
2、默认值是False
fill 1、指定填充pack()分配的空间;
2、默认值是NONE,表示保持子组件的原始尺寸;
3、还可以使用的值有:"x"(水平填充),"y"(垂直填充)和 "both"(水平和垂直填充)。
in_ 1、将该组件放到该选项指定的组件中;
2、指定的组件必须是该组件的父组件。
ipadx 指定水平方向上的内边距。
ipady 指定垂直方向上的内边距。
padx 指定水平方向上的外边距。
pady 指定垂直方向上的外边距。
side 1、指定组件的放置位置;
2、默认值是 "top"
3、还可以设置的值有:"left""bottom""right"

某些参数通过字符串来指定,但是并不会直接使用字符串,而是会用tkinter中预定义的值:

# -anchor and -sticky
N='n'
S='s'
W='w'
E='e'
NW='nw'
SW='sw'
NE='ne'
SE='se'
NS='ns'
EW='ew'
NSEW='nsew'
CENTER='center'

# -fill
NONE='none'
X='x'
Y='y'
BOTH='both'

# -side
LEFT='left'
TOP='top'
RIGHT='right'
BOTTOM='bottom'

所以在代码中会看到tkinter.TOP这样的值。

最终得到的结果如下:

在这里插入图片描述

右侧红色部分就是渲染的结果,可以看到Frame就是一个矩形的图形,它本身意义不大,通常用来作为其它组件的容器。

Label

Label通常是一个带字符串的标签,创建方式如下:

tkinter.Label(fram, text='Text to find:').pack(side=tkinter.LEFT)

通常也是创建和布局两部分,这里直接组合在一起了,显示结果如下:

在这里插入图片描述

下面是另外一个例子:

status = tkinter.Label(master, text="Check status here", bd=1, relief=tkinter.SUNKEN, anchor=tkinter.W)
status.pack(side=tkinter.BOTTOM, fill=tkinter.X)

显示结果如下:

在这里插入图片描述

Entry也接收两个部分的参数:

  • 父组件;
  • 可选参数,其可选值如下:
可选项 描述
anchor 1、文本或图像在背景内容区的位置;
2、可选值为"n""ne""e""se""s""sw""w""nw""center"
3、默认为center
bg 标签背景颜色。
bd 标签的大小,默认为2个像素。
bitmap 指定标签上的位图,如果指定了图片,则该选项忽略。
cursor 鼠标移动到标签时,光标的形状,可以设置为arrowcirclecrossplus等。
font 设置字体。
fg 设置前景色。
height 标签的高度,默认值是0。
image 设置标签图像。
justify 1、定义对齐方式;
2、可选值有:LEFTRIGHTCENTER
3、默认为CENTER
padx x轴间距,以像素计,默认1。
pady y轴间距,以像素计,默认1。
relief 1、边框样式;
2、可选的有:FLATSUNKENRAISEDGROOVERIDGE
3、默认为FLAT
text 设置文本,可以包含换行符(\n)。
textvariable 1、标签显示Tkinter变量,StringVar类型;
2、如果变量被修改,标签文本将自动更新。
underline 设置下划线,默认-1,如果设置1,则是从第二个字符开始画下划线。
width 设置标签宽度,默认值是0,自动计算,单位以像素计。
wraplength 设置标签文本为多少行显示,默认为0。

Entry

Entry表示的是文本框,可以在里面输入文本,并在后台处理。它的创建和布局:

self.edit = tkinter.Entry(fram, width=30)
self.edit.pack(side=tkinter.LEFT, fill=tkinter.BOTH, expand=1, pady=2, padx=(4, 4))

Entry也接收两个部分的参数:

  • 父组件;
  • 可选参数,其可选值如下:
可选项 描述
bg 输入框背景颜色。
bd 边框的大小,默认为2个像素。
cursor 光标的形状设定,如arrowcirclecrossplus等。
font 文本字体。
exportselection 默认情况下,你如果在输入框中选中文本,默认会复制到粘贴板,如果要忽略这个功能刻工艺设置exportselection=0
fg 1、文字颜色;
2、值为颜色或颜色代码,如:'red''#ff0000'
highlightcolor 文本框高亮边框颜色,当文本框获取焦点时显示。
justify 显示多行文本的时候,设置不同行之间的对齐方式,可选项包括LEFTRIGHTCENTER
relief 1、边框样式,设置组件3D效果;
2、可选的有:FLATSUNKENRAISEDGROOVERIDGE
3、默认为FLAT
selectbackground 选中文字的背景颜色。
selectborderwid 选中文字的背景边框宽度。
selectforeground 选中文字的颜色。
show 指定文本框内容显示为字符,值随意,满足字符即可。如密码可以将值设为show="*"
state 默认为state=NORMAL, 文框状态,分为只读和可写,值为:normal/disabled
textvariable 文本框的值,是一个StringVar对象。
width 文本框宽度。
xscrollcommand 设置水平方向滚动条,一般在用户输入的文本框内容宽度大于文本框显示的宽度时使用。

执行结果如下:

【Python应用】tkinter简介_第3张图片

Entry与前面介绍的组件的差别在于它是可交互的,所以还有额外的事情可以做,比如说当输入内容之后按下Enter键来触发事件:

self.edit.bind("", (lambda event: self.search_bar()))

这里通过bind()函数绑定一个事件,该事件回调search_bar()函数:

def search_bar(self):
    print("Input: %s" % self.edit.get())
    pass

以上是一个示例函数,它做的事情就是打印获取到的值,执行结果如下:

【Python应用】tkinter简介_第4张图片

在Entry文本框中输入内容之后按下Enter键就会在命令行窗口打印文本框中的内容。

另外再介绍一个函数:

self.edit.focus_set()

它设置文本框为焦点,这样打开程序的时候鼠标就会直接在该文本框中,可以直接进行输入。

除了使用Enter键,另外的选择就是在旁边增加按钮,下面将介绍。

Button

Button增加一个按键,创建和布局的方式如下:

butt = tkinter.Button(fram, text='Search', relief=tkinter.GROOVE, command=self.search_bar)
butt.pack(side=tkinter.RIGHT, padx=(4, 4))

Button类的参数如下:

  • 父组件;
  • 可选参数:
可选项 描述
activebackground 当鼠标放上去时,按钮的背景色。
activeforeground 当鼠标放上去时,按钮的前景色。
bd 按钮边框的大小,默认为2个像素。
bg 按钮的背景色。
command 按钮关联的函数,当按钮被点击时,执行该函数。
fg 按钮的前景色(按钮文本的颜色)。
font 文本字体。
height 按钮的高度。
highlightcolor 要高亮的颜色。
image 按钮上要显示的图片。
justify 显示多行文本的时候,设置不同行之间的对齐方式,可选项包括LEFTRIGHTCENTER
padx 按钮在x轴方向上的内边距(padding),是指按钮的内容与按钮边缘的距离。
pady 按钮在y轴方向上的内边距(padding)。
relief 1、边框样式,设置组件3D效果;
2、可选的有:FLATSUNKENRAISEDGROOVERIDGE
3、默认为FLAT
state 1、设置按钮组件状态;
2、可选的有NORMALACTIVEDISABLED
3、默认NORMAL
underline 1、下划线;
2、默认按钮上的文本都不带下划线;
3、取值就是带下划线的字符串索引,为0时,第一个字符带下划线,为1时,前两个字符带下划线,以此类推。
width 按钮的宽度,如未设置此项,其大小以适应按钮的内容(文本或图片的大小)。
wraplength 限制按钮每行显示的字符的数量。
text 按钮的文本内容。
anchor 锚选项,控制文本的位置,默认为中心。

本例中的command指定了在Entry中的search_bar()函数,所以按键之后该函数也会被回调,结果跟Entry的一致。

执行结果如下:

【Python应用】tkinter简介_第5张图片

Panedwindow

PanedWindow组件是一个空间管理组件。跟Frame组件类似,都是为组件提供一个框架,不过PanedWindow允许让用户调整应用程序的空间划分。

PanedWindow组件会为每一个子组件生成一个独立的窗格,用户可以自由调整窗格的大小。下面是一个例子:

paned = ttk.Panedwindow(root, orient=tkinter.HORIZONTAL)
paned.pack(fill=tkinter.BOTH, expand=True, padx=(4, 4))

frame_left = ttk.Frame(paned, height=800, relief="groove")
frame_right = ttk.Frame(paned, relief="groove")

paned.add(frame_left, weight=2)
paned.add(frame_right, weight=10)

显示的结果:

【Python应用】tkinter简介_第6张图片

红框中通过两个Frame分割了Panedwindow。

Menu

Menu用来创建菜单栏。

tkinter提供了三种类型的菜单,分别是:toplevel(主目录菜单),pull-down(下拉式菜单),pop-up(弹出式菜单,或称快捷式菜单)。

创建Menu的方式:

menubar = tkinter.Menu(root)
file_menu = tkinter.Menu(menubar, tearoff=0)
generate_menu = tkinter.Menu(menubar, tearoff=0)

Menu除了接收父组件,还包含一系列的可选参数:

可选项 描述
accelerator 1、设置菜单项的快捷键,快捷键会显示在菜单项目的右边,比如accelerator = "Ctrl+O"表示打开;
2、注意,此选项并不会自动将快捷键与菜单项连接在一起,必须通过按键绑定来实现。
command 选择菜单项时执行的callback函数。
label 定义菜单项内的文字。
menu 此属性与add_cascade()方法一起使用,用来新增菜单项的子菜单项。
selectcolor 指定当菜单项显示为单选按钮或多选按钮时选择中标志的颜色。
state 定义菜单项的状态,可以是normalactivedisabled
onvalue/offvalue 1、默认情况下,variable选项设置为1表示选中状态,反之设置为0;
2、设置offvalue/onvalue的值可以自定义未选中状态的值。
tearoff 1、如果此选项为True,在菜单项的上面就会显示一个可选择的分隔线;
2、注意:分隔线会将此菜单项分离出来成为一个新的窗口。
underline 设置菜单项中哪一个字符要有下画线。
value 1、设置按钮菜单项的值
2、在同一组中的所有按钮应该拥有各不相同的值;
3、通过将该值与 variable 选项的值对比,即可判断用户选中了哪个按钮。
variable 当菜单项是单选按钮或多选按钮时,与之关联的变量。

本例创建了两个Menu,第一个是父Menu,后面的是子Menu。前者的父Menu组成一组横向的菜单,而后者的子Menu组成下拉的菜单。首先是横向的菜单:

menubar.add_cascade(label="File", menu=file_menu)
menubar.add_cascade(label="Generate", menu=generate_menu)

然后通过root的config()函数配置root的属性以显示菜单:

root.config(menu=menubar)

得到的结果如下:

【Python应用】tkinter简介_第7张图片

不过前面创建的只是空的菜单,下面是添加后续内容:

# Create parent menu.
menubar = tkinter.Menu(root)

# Create child menu.
file_menu = tkinter.Menu(menubar, tearoff=0)
file_menu.add_command(label="Open JSON file...",
			command=self.load_from_json)
file_menu.add_command(label="Open binary file...",
			command=self.load_from_bin)
generate_menu = tkinter.Menu(menubar, tearoff=0)
generate_menu.add_command(label="Generate binary...",
			command=self.generate_bin)

# Add child menu to parent menu.
menubar.add_cascade(label="File", menu=file_menu)
menubar.add_cascade(label="Generate", menu=generate_menu)

# Draw menu.
root.config(menu=menubar)

最终得到的结果:

【Python应用】tkinter简介_第8张图片

这里的load_from_json()等回调函数的实现不在本文的涉及范围,所以这里不作说明。

Treeview和Scrollbar

Treeview组件主要是提供多栏的显示功能。在设计时也可以在左边栏设计成树状结构或是称层次结构,用户可以显示或隐藏任何部分。它可以跟Scrollbar一起使用,用来滚动显示Treeview组件的可见范围。

下面是创建Treeview的示例:

frame_left = ttk.Frame(paned, height=800, relief="groove")
self.left = ttk.Treeview(frame_left, show="tree")

Treeview的可见参数:

可选项 描述
class_ 部件分类名称,建立后不能改变。
columns 序列的识别码字符串,该序列不包含图标列的识别码,第一列图标列的识别码永远为"#0"
cursor 鼠标悬停在按钮上时显示的鼠标,内定为空字符串,继承父部件的选项。
displaycolumns 指定各列显示与否及其顺序,"#all"代表全部,或整数的列表,识别码列表,各列的内容必须按此顺序提供。
height 部件的行数。
padding 部件内部子部件的外部间隔,可以是单一尺寸,或最多4-tuple,顺序为(left, top, right, bottom),省略部份由其它代替,如a=(a, a, a, a)(a, b) = (a, b, a, b)
select 1、项目被选择的模式;
2、可选项有:‘browse’(单选),‘extended’(可多选),‘none’(不可选)。
show 1、'tree'不显示表头显示图标栏;
2、'headings'不显示图标栏显示表头;
3、'tree headings'显示表头及图标栏(预设);
4、''表头及图标栏都不显示。
style 生成部件的样式。
takefocus 指定该组件是否接受输入焦点(用户可以通过tab键将焦点转移上来),默认为 false

下面是创建Scrollbar的示例:

self.tree_scroll = ttk.Scrollbar(frame_left, orient="vertical", command=self.left.yview)

Scrollbar的可见参数:

可选项 描述
bg 设置背景颜色。
bd 指定边框宽度,通常是2像素。
cursor 指定当鼠标在上方飘过的时候的鼠标样式。
orient 指定绘制"horizontal"(垂直滚动条)还是"vertical"(水平滚动条)。
highlightbackground 指定当滚动条没有获得焦点的时候高亮边框的颜色。
highlightcolor 指定当滚动条获得焦点的时候高亮边框的颜色。
jump 指定当用户拖拽滚动条时的行为。
relief 指定边框样式, 默认值是"sunken"
command 当滚动条更新时回调的函数 通常的是指定对应组件的xview()yview()方法。
takefocus 指定该组件是否接受输入焦点(用户可以通过 tab 键将焦点转移上来), 默认值是 True
width 设置滚动条的宽度, 默认值是16像素。

Treeview还包含一些有用的函数:

self.left.configure(yscrollcommand=self.tree_scroll.set)
self.left.bind("<>", self.on_config_page_select_change)
self.left.bind("",  lambda e: self.in_left.set(True))
self.left.bind("",  lambda e: self.in_left.set(False))
self.left.bind("",  self.on_tree_scroll)

第一个函数configure()用于设置样式,与前面创建的Scrollbar匹配。

后面的bind()是绑定时间的,后面的比较好理解,第一个<<>>需要解释下:

  • << TreeviewSelect>>,代表选择变化是发生;
  • << TreeviewOpen>>,item的open=True时发生;
  • << TreeviewClose>>,item的open=False时发生。

上面的item可以通过Treeview.focus()Treeview.selection()可获取。

最终结果:

【Python应用】tkinter简介_第9张图片

注意这里没有对绑定的回调函数进行说明,这不在本文的讨论范围内。不过还需要介绍如何往Tree中增加内容,其使用的函数是:

self.left.insert('', 'end', text=key)

insert()函数接收如下的参数:

  • parent:对于表格类型的Treeview,parent一般为空。对于树形类型的Treeview,parent为父节点;
  • index:指明在何处插入新的项;可以是'end',也可以是数字;比如,如果要让新插入的项成为第一个子节点或者在第一行,index就设为0;如果是第二个子节点或者第二行,就是设置index为1;如果在最末端插入项,就设置index='end'
  • iid:如果没有赋值,就使用系统自动生成的id;如果输入了id,必须保证与现有的id不重复;否则系统会自动生成id;
  • **kw:设置插入项的属性,支持的属性有:
可选项 描述
image 显示图像。
open 针对树形结构,确认插入的项是打开还是折叠状态。True打开,False为折叠。
tags 为新插入的项设置tag标签。
text 显示文字。
values 在表格结构中,要显示的数值;这些数值是按照逻辑结构赋值的,也就是按照columns设定的列次序来赋值;如果输入的个数少于columns指定列数,则插入空白字符串。

得到的示例结果如下:

【Python应用】tkinter简介_第10张图片

Canvas

Canvas属于tkinter,就是画布,可以将图形,文本,小部件或框架放置在画布上。

创建画布的方式:

self.conf_canvas = tkinter.Canvas(frame_right, highlightthickness=0)

第一个参数是父组件,第二个参数是可选的,其可选值如下:

可选项 描述
bd 边框宽度,单位像素,默认为2像素。
bg 背景色。
confine 如果为 True(默认),画布不能滚动到可滑动的区域外。
cursor 光标的形状设定,如arrowcirclecrossplus 等。
height 高度。
highlightcolor 要高亮的颜色。
relief 边框样式,可选值为FLATSUNKENRAISEDGROOVERIDGE。 默认为FLAT
scrollregion 一个元组(w, n, e, s) ,定义了画布可滚动的最大区域,w为左边,n为头部,e为右边,s为底部。
width 画布在x坐标轴上的大小。
xscrollincrement 用于滚动请求水平滚动的数量值。
xscrollcommand 水平滚动条,如果画布是可滚动的,则该属性是水平滚动条的set()方法。
yscrollincrement 类似xscrollincrement,但是垂直方向。
yscrollcommand 垂直滚动条,如果画布是可滚动的,则该属性是垂直滚动条的set()方法。

Canvas也可以跟Scrollbar绑定:

self.page_scroll = ttk.Scrollbar(frame_right, orient="vertical", command=self.conf_canvas.yview)
self.conf_canvas.configure(yscrollcommand=self.page_scroll.set)

Canvas最重要的是一系列的create_xx()函数,比如下面的代码创建了一个组件:

self.conf_canvas.create_window(0, 0, window=self.right_grid, anchor='nw')

Canvas也支持bind()函数:

self.conf_canvas.bind('',  lambda e: self.in_right.set(True))
self.conf_canvas.bind('',  lambda e: self.in_right.set(False))
self.conf_canvas.bind("", self.on_canvas_configure)
self.conf_canvas.bind_all("", self.on_page_scroll)

filedialog

用于打开一个选择文件的窗口:

    self.last_dir = '.'    
    path = filedialog.askopenfilename(
            initialdir=self.last_dir,
            title="Load file",
            filetypes=(("%s files" % file_type, "*.%s" % file_ext), ("all files", "*.*"))
            )

执行之后,选择“File->Open JSON file…”,结果如下:

【Python应用】tkinter简介_第11张图片

选择之后就得到path可以在代码中使用该文件。

你可能感兴趣的:(Python,python,tkinter)