part11-2 Python图形界面编程(Tkinter常用组件对话框(Dialog)菜单Canvas绘图)
Posted 远方那一抹云
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了part11-2 Python图形界面编程(Tkinter常用组件对话框(Dialog)菜单Canvas绘图)相关的知识,希望对你有一定的参考价值。
五、 Tkinter 常用组件
Tkinter 各组件的详细用法还需要掌握,也就是掌握各个“积木块”的的详细功能。
1、 使用 ttk 组件
在前面直接使用的 tkinter 模块下的 GUI 组件看上去并不美观。为此 Tkinter 引了一个 ttk 组件作为补充,并使用功能更强大的 Combobox 取代原来的 Listbox,且新增了 LabeledScale(带标签的Scale)、Notebook(多文档窗口)、Progressbar(进度条)、Treeview(树)等组件。
ttk 是一个放在 tkinter 包下的模块,使用方式与使用普通的 Tkinter 组件基本相同,只要导入 ttk 模块即可。ttk 组件的使用示例如下代码所示:
from tkinter import * from tkinter import ttk class App: def __init__(self, master): self.master = master self.initWidgets() # self.init_ttk() def initWidgets(self): cb = Listbox(self.master, font=24) # 为 Listbox 设置列表项 for s in (\'Python\', \'Linux\', \'HTML\'): cb.insert(END, s) cb.pack(side=LEFT, fill=X, expand=YES) f = Frame(self.master) f.pack(side=RIGHT, fill=BOTH, expand=YES) lab = Label(self.master, text=\'我的标签\', font=24) lab.pack(side=TOP, fill=BOTH, expand=YES) bn = Button(self.master, text=\'我的按钮\') bn.pack() def init_ttk(self): # ttk 使用 Combobo 取代 Listbox cb = ttk.Combobox(self.master, font=24) # 为 Combobox 设置列表项 cb[\'value\'] = (\'Python\', \'Linux\', \'HTML\') cb.pack(side=LEFT, fill=X, expand=YES) f = ttk.Frame(self.master) f.pack(side=RIGHT, fill=BOTH, expand=YES) lab = ttk.Label(self.master, text=\'我的标签\', font=24) lab.pack(side=TOP, fill=BOTH, expand=YES) bn = ttk.Button(self.master, text=\'我的按钮\') bn.pack() root = Tk() root.title("简单事件处理") App(root) root.mainloop()
上面代码中, init_ttk() 方法是使用 ttk 组件的代码。现在在__init__
函数中注释了 self.init_ttk(),直接运行这段代码可以看到图十三中1图的界面。将 self.init_ttk() 取消注释,并且对 self.initWidgets() 添加注释后,再运行代码,看到的是图十三中2图的界面。
图十三 Tkinter组件与ttk组件的运行界面
对比两个界面上的 button 可以看出,ttk 下的Button 接近 Windows 7 本地平台网格,显得更好看些,这就是 ttk 组件优势。
2、 Variable 类
Tkinter 支持将多个 GUI 组件与变量进行双向绑定,执行这种双向绑定后编程非常方便。
(1)、如果在程序中改变变量的值,GUI 组件的显示内容或值会随之改变。
(2)、当 GUI 组件的内容发生改变时(如用户输入),变量的值也会随之改变。
要让 Tkinter 组件与变量进行双向绑定,只要为这些组件指定 variable(绑定组件的 value)、textvariable(绑定组件显示的文本)等属性即可。双向绑定还有一个限制,就是 Tkinter 不允许将组件和普通变量进行绑定,只能和 tkinter 包下的 Variable 类的子类进行绑定。该类包含的子类如下:
(1)、StringVar():用于包装 str 值的变量。
(2)、IntVar():用于包装整型值的变量。
(3)、DoubleVar():用于包装浮点值的变量。
(4)、BooleanVar():用于包装 bool 值的变量。
使用 Variable 的 set() 方法可以设置变量值,get() 方法可以得到变量值。下面代码实现将 Entry 组件与 StringVar 进行双向绑定,在程序中可通过 StringVar 改变 Entry 输入框显示的内容,也可通过该 StringVar 获取 Entry 输入框中的内容。
from tkinter import * from tkinter import ttk class App: def __init__(self, master): self.master = master self.initWidgets() def initWidgets(self): self.st = StringVar() # 创建 Label 组件,将其 textvariable 绑定到 self.st 变量 ttk.Entry(self.master, textvariable=self.st, width=24, font=(\'StSong\', 20, \'bold\'), foreground=\'red\').pack(fill=BOTH, expand=YES) # 创建 Frame 作为容器 f = Frame(self.master) f.pack() # 创建两个按钮,并放入 Frame 中 ttk.Button(f, text=\'改变\', command=self.change).pack(side=LEFT) ttk.Button(f, text=\'获取\', command=self.get).pack(side=LEFT) def change(self): books = (\'Python 入门\', \'Python 进阶\', \'Python 核心\') import random # 改变 self.st 变量值,与之绑定的 Entry 的内容随之改变 self.st.set(books[random.randint(0, 2)]) def get(self): from tkinter import messagebox # 获取 self.st 变量的值,实际上就是获取与之绑定的 Entry 中的内容 # 并使用消息框显示 self.st 变量的值 messagebox.showinfo(title=\'输入内容\', message=self.st.get()) root = Tk() root.title(\'variable 测试\') App(root) root.mainloop()
上面代码中的 self.st.set(books[random.randint(0, 2)]) 行代码调用 StringVar 改变变量的值,这样与该变量绑定的 Entry 中显示的内容会随之改变;另一行 messagebox.showinfo(title=\'输入内容\', message=self.st.get()) 代码获取 StringVar 变量的值,实际上是获取与该变量绑定的 Entry 中的内容。
运行这段代码,单击界面上的“改变”按钮,可看到输入框中的内容会随之改变;单击“获取”按钮就会弹出一个消息框,并显示在 Entry 输入框中输入的内容。运行结果如图十四所示。
图十四 使用variable类设置和获取输入框值
3、 使用 compound 选项
还可以为按钮或 Label 等组件同时指定 text 和 image 选项。text 选项用于指定该组件上的文本,image 选项用于显示该组件上的图片。同时指定这两个选项时,image 会覆盖 text,可通过 compound 选项来控制 text 不被 image 覆盖掉。
compound 选项的属性值有:
(1)、None:图片覆盖文字。
(2)、LEFT常量(值为\'left\'字符串):图片在左,文本在右。
(3)、RIGHT常量(值为\'right\'字符串):图片在右,文本在左。
(4)、TOP常量(值为\'top\'字符串):图片在上,文本在下。
(5)、BOTTOM常量(值为\'bottom\'字符串):图片在底,文本在上。
(6)、CENTER常量(值为\'center\'字符串):文本在图片上方。
下面代码使用多个单选按钮来控制 Label 的 compound 选项,代码如下:
from tkinter import * from tkinter import ttk class App: def __init__(self, master): self.master = master self.initWidgets() def initWidgets(self): # 创建一个位图 bm = PhotoImage(file=\'baidu.png\') # 创建一个 Entry ,同时指定 text 和 image self.label = ttk.Label(self.master, text=\'Python学\\n习路线\', \\ image=bm, font=(\'StSong\', 20, \'bold\'), foreground=\'#000\') self.label.bm = bm # 设置 Label 默认的 compound 为 None self.label[\'compound\'] = None self.label.pack() # 创建 Frame 容器,用于装多个 Radiobutton f = ttk.Frame(self.master) f.pack(fill=BOTH, expand=YES) compounds = (\'None\', \'LEFT\', \'RIGHT\', \'TOP\', \'BOTTOM\', \'CENTER\') # 定义一个 StringVar 变量,用作绑定 Radiobutton 的变量 self.var = StringVar() self.var.set(\'None\') # 使用循环创建多个 Radiobutton(单选按钮) 组件 for val in compounds: rb = Radiobutton(f, text=val, padx=20, variable=self.var, command=self.change_compound, value=val).pack(side=LEFT, anchor=CENTER) # 实现 change_compound 方法,用于动态改变 Label 的 compound 选项 def change_compound(self): self.label[\'compound\'] = self.var.get().lower() root = Tk() root.title(\'compound测试\') App(root) root.mainloop()
上面代码中,这行 elf.label[\'compound\'] = None 代码设置 Label 默认的 compound 选项为 None,此时该 Label 默认图片覆盖文字;另一行 self.label[\'compound\'] = self.var.get().lower() 代码会根据单选按钮的值(单选按钮与 self.var 绑定)来确定 Label 的 compound 选项。
运行代码,首先看到的是 Label 只有显示图片,文字不显示,这是由 compound 选项为 None 设置的效果,可点击下边的单选按钮,就可看到文字和图片位置的改变。运行效果如图十五所示。
图十五 将 compound 设为 TOP 让图片在上
4、 Entry 和 Text 组件
这两个都是输入框组件,其中 Entry 是单行输入框组件,Text 是多行输入框组件,Text 还可以为不同的部分添加不同的样式,甚至响应事件。
这两个都可通过 get() 方法来获取文本框中的内容;也可通过 insert() 方法来改变文本框中的内容。
要删除这两个组件中的内容,需要使用 delete(self, first, last=None) 方法,该方法删除从 first 到 last 索引之间的内容。对于这两个组件使用的索引方法是不同的。Entry 是单行文本,索引比较简单,例如指定(3,8)表示指定的是第4个到第8个字符。但是Text 是多行文本框组件,它的索引要同时指定行号和列号,它的行号从1开始,列号从0开始。例如 1.0 表示的是第1行、第1列的字符,如果要指定第2行第3个字符到第3行第7个字符,索引应指定为 (2.2, 3.6)。
另外,Entry支持双向绑定(前面代码中已经使用过),可将 Entry 与变量绑定在一起,这样在程序中就可通过该变量来改变、获取Entry 组件中的内容。
关于这两个组件的用法示例如下:
from tkinter import * from tkinter import ttk from tkinter import messagebox class App: def __init__(self, master): self.master = master self.initWidgets() def initWidgets(self): # 第1步:创建 Entry 组件 self.entry = ttk.Entry(self.master, width=44, font=(\'StSong\', 14), foreground=\'orange\') self.entry.pack(fill=BOTH, expand=YES) # 第2步:创建 Text 组件 self.text = Text(self.master, width=44, height=4, font=(\'StSong\', 14), foreground=\'blue\') self.text.pack(fill=BOTH, expand=YES) # 第3步:创建 Frame 容器,用于放5个按钮组件 f = Frame(self.master) f.pack() # 第4步:创建5个按钮,将其放入 Frame 中 ttk.Button(f, text=\'开始输入\', command=self.insert_start).pack(side=LEFT) ttk.Button(f, text=\'编辑处插入\', command=self.insert_edit).pack(side=LEFT) ttk.Button(f, text=\'结尾输入\', command=self.insert_end).pack(side=LEFT) ttk.Button(f, text=\'获取Entry\', command=self.get_entry).pack(side=LEFT) ttk.Button(f, text=\'获取 Text\', command=self.get_text).pack(side=LEFT) def insert_start(self): # 在 Entry 和 Text 的开始处插入内容 self.entry.insert(0, \'Linux\') self.text.insert(0.0, \'Linux\') def insert_edit(self): # 在 Entry 和 Text 的编辑处插入内容 self.entry.insert(INSERT, \'Python\') self.text.insert(INSERT, \'Python\') def insert_end(self): # 在 Entry 和 Text 的结尾处插入内容 self.entry.insert(END, \'Html\') self.text.insert(END, \'Html\') def get_entry(self): messagebox.showinfo(title=\'输入内容\', message=self.entry.get()) def get_text(self): messagebox.showinfo(title=\'输入内容\', message=self.text.get(0.0, END)) root = Tk() root.title("Entry测试") App(root) root.mainloop()
上面代码中,首先创建了一个 Entry 组件和一个 Text 组件。在接下来的事件响应函数中,调用了这两个组件的 insert() 方法分别在开始位置、指定位置、编辑处、结尾处插入内容,通过该 insert() 方法的第一个参数可以指定要插入内容的位置。
要获取 Entry 组件和 Text 组件的内容,通过调用 get() 方法来实现。在调用 Text 组件的 insert()、get() 方法时,要注意坐标参数的写法。
运行这段代码,向 Entry、Text 中插入一些内容,单击界面上的 “获取 Text” 按钮,可以看到如图十六所示的界面。
图十六 获取文本框中的内容
Text是一个功能强大的“富文本”编辑组件,使用 Text 不仅可能插入文本,还可以插入图片。
(1)、image_create(self,index,cnf={},**kw) 方法可以插入图片;
(2)、还可以设置文本内容的格式,使用的方法是:insert(self, index, chars, *args),最后一个参数传入多个 tag 进行控制,实现图文并茂效果。
此外, Text 组件还可能使用滚动条,在内容较多时实现滚动显示。要实现滚动显示需要进行双向关联。可分成两步操作:
(1)、将 Scrollbar 的 command 设为目标组件的 xview 或 yview,其中 xview 控制水平滚动,yview 控制垂直滚动。
(2)、将目标组件的 xscrollcommand 或 yscrollcommand 属性设为 Scrollbar 的set 方法。
下面代码使用 Text 来实现一个图文并茂的界面。
from tkinter import * from tkinter import ttk class App: def __init__(self, master): self.master = master self.initWidgets() def initWidgets(self): # 创建第一个 Text 组件 text1 = Text(self.master, height=27, width=32) # 创建图片 book = PhotoImage(file=\'images/pyhistory.png\') text1.bm = book text1.insert(END, \'\\n\') # 在结尾处插入图片 text1.image_create(END, image=book) text1.pack(side=LEFT, fill=BOTH, expand=YES) # 创建第二个 Text 组件 text2 = Text(self.master, height=33, width=50) text2.pack(side=LEFT, fill=BOTH, expand=YES) self.text = text2 # 创建 Scrollbar 组件,设置该组件与 Text2 的垂直滚动关联 scroll = Scrollbar(self.master, command=text2.yview) scroll.pack(side=RIGHT, fill=Y) # 设置 Text 的垂直滚动影响 scroll 滚动条 text2.configure(yscrollcommand=scroll.set) # 配置名为 title 的样式 text2.tag_configure(\'title\', font=(\'楷体\', 20, \'bold\'), foreground=\'red\',justify=CENTER, spacing3=20) text2.tag_configure(\'detail\', foreground=\'darkgray\', font=(\'微软雅黑\', 11, \'bold\'), spacing2=20, # 设置行间距 spacing3=15) # 设置段间距 text2.insert(END, \'\\n\') # 插入文本内容,设置使用 title 样式 text2.insert(END, \'Python语言介绍\\n\', \'title\') # 创建图片 star = PhotoImage(file=\'images/g016.gif\') text2.bm = star details = (\'Python 是一门古老的编程语言,发展到今天,已经应用到多个行业上。\\n\', \'Python 有两个主要的版本,分别是 2.X 和 3.x 版本,现在官方推荐都转到 3.x 版本上。\\n\', \'Python 主要应用领域有Web开发、大数据分析、人工智能。\' + \\ \'以及科学计算、金融等领域\\n\') # 采用循环插入多条介绍信息 for de in details: text2.image_create(END, image=star) text2.insert(END, de, \'detail\') url = [\'https://www.baidu.com\', \'https://www.python.org\'] name = [\'百度主页\', \'Python官网\'] m = 0 for each in name: # 为每个链接创建单独的配置 text2.tag_configure(m, foreground=\'blue\', underline=True, font=(\'微软雅黑\', 13, \'bold\')) text2.tag_bind(m, \'<Enter>\', self.show_arrow_cursor) text2.tag_bind(m, \'<Leave>\', self.show_common_cursor) # 使用 handlerAdaptor 包装,将当前链接参数传入事件处理方法中 text2.tag_bind(m, \'<Button-1>\', self.handlerAdaptor(self.click, x=url[m])) text2.insert(END, each + \'\\n\', m) m += 1 def show_arrow_cursor(self, event): # 光标移上去时变成箭头 self.text.config(cursor=\'arrow\') def show_common_cursor(self, event): # 光标移出去恢复原样 self.text.configure(cursor=\'xterm\') def click(self, event, x): import webbrowser # 使用默认浏览器打开链接 webbrowser.open(x) def handlerAdaptor(self, fun, **kwds): return lambda event, fun=fun, kwds=kwds: fun(event, **kwds) root = Tk() root.title("Text测试") App(root) root.mainloop()
上面代码中,第29-34行使用 Text 的tag_configure(也写作 tag_config)方法创建了 title 和 detail 两个 tag,每个 tag 可用于控制一段文本的格式、事件等。接下来使用 title tag 插入一个标题内容,标题内容的格式将受到 title tag 的控制;接着再使用循环插入了三条受 detail tag 控制的描述信息,每次在插入描述信息之前都先插入一张图片。
第54-59行代码在循环内创建了 tag,并调用 Text 组件的 tag_bind() 方法为 tag 绑定事件处理方法。这里要让每链接打开不同页面,因此要为每条链接内容分别创建不同的 tag,从而实现每个链接打开对应的页面。
运行上面的代码,看到图文界面如图十七所示。
图十七 使用Text实现图文并茂的界面
5、 Radiobutton 和 Checkbutton 组件
Radiobuton 组件是单选按钮,可为该组件绑定一个方法或函数,当单选按钮被选择时,该方法或函数就会被触发。如果要将多个Radiobutton 编为一组,需要将多个 Radiobutton 绑定到同一个变量。当这组 Radiobutton 的其中一个单选按钮被选中时,该变量就会随之改变;反过来,该变量发生改变时,这组 Radiobutton 也会自动选中该变量值所对应的单选按钮。关于 Radiobutton 组件的用法示例如下:
from tkinter import * from tkinter import ttk class App: def __init__(self, master): self.master = master self.initWidgets() def initWidgets(self): # 创建一个 Label 组件 ttk.Label(self.master, text=\'选择喜欢的图书:\').\\ pack(fill=BOTH, expand=YES) self.intVar = IntVar() # 定义元组 books = (\'Python 基础入门\', \'Python 进阶\', \'Python 核心编程\', \'Python 应用编程\') i = 1 # 采用循环创建多个 Radiobutton for book in books: ttk.Radiobutton(self.master, text=book, variable=self.intVar, # 将 Radiobutton 绑定到 self.intVar 变量 command=self.change, # 将选中事件绑定到 self.change 方法 value=i).pack(anchor=W) i += 1 # 设置 Radiobutton 绑定的变量值为 2 # 则默认选中 value 为 2 的 Radiobutton self.intVar.set(2) def change(self): from tkinter import messagebox # 通过 Radiobutton 绑定变量获取选中的单选钮 messagebox.showinfo(title=\'选中的图书\', message=self.intVar.get()) root = Tk() root.title("Radiobutton 测试") App(root) root.mainloop()
上面代码中使用循环创建多个 Radiobutton 组件,第20行代码指定将这些 Radiobutton 绑定到 self.initVar 变量,这样这些Radiobutton 位于同一组内;第21行代码为这组 Radiobutton 的选中事件绑定了 self.change 方法,每次选择不同的单选按钮时,就会触发对象的 change() 方法。
运行上面的代码,从输出界面可看到默认选中第二个单选钮,这是由第26行代码进行设置的。当选中其它单选钮时,就会弹出提示框显示用户的选择项。运行结果如图十八所示。
图十八 选中不同的单选钮
单选钮不仅可以显示文本,还可以显示图片,使用到的是 image 选项。如果要让图片和文字同时显示,也可通过 compound 选项进行控制,如果不指定 compound,该选项默认为 None,这意味着只显示图片。下面代码示例了带图片的单选钮。
from tkinter import * from tkinter import ttk class App: def __init__(self, master): self.master = master self.initWidgets() def initWidgets(self): # 创建一个 Label 组件 ttk.Label(self.master, text=\'选中你喜欢的兵种:\').\\ pack(fill=BOTH, expand=YES) self.intVar = IntVar() # 定义元组 races_dict = {\'z.png\': \'虫族\', \'p.png\': \'神族\', \'t.png\': \'人族\'} # 采用循环创建多个 Radiobutton for i, rc in enumerate(races_dict.keys(), 1): bm = PhotoImage(file=\'images/\' + rc) r = ttk.Radiobutton(self.master, image=bm, text=races_dict[rc], compound=RIGHT, # 图片在文字右边 variable=self.intVar, # 将 Radiobutton 绑定到 self.intVar 变量 command=self.change, # 将选中事件绑定到 self.change 方法 value=i) r.bm = bm r.pack(anchor=W) # 设置默认选中 value 为 2 的单选钮 self.intVar.set(2) def change(self): pass root = Tk() root.title(\'Radiobutton 测试\') # 改变窗口图标 root.iconbitmap(\'images/logo.ico\') App(root) root.mainloop()
上面代码中的20~22行为 Radiobutton 同时指定了 image 和 text 选项,并指定 compound 选项为 RIGHT,这时该单选钮的图片显示在文字的右边。此外,第35行代码设置了窗口自定义的图标。现在运行这段代码,可以看到如图十九所示的界面。
图十九 带图标的单选钮
Checkbutton 与 Radiobutton 很相似,但 Checkbutton 可选择多项,与每组 Radiobutton 只能选择一项不同。Checkbutton 同样可显示文字和图片,内样可以绑定变量,同样可以为选中事件绑定函数和处理方法。由于 Checkbutton 可以同时选中多项,因此需要为每个 Checkbutton 都绑定一个变量。
Checkbutton 就像开头一样,支持两个值:开头打开和关闭的值。因此,在创建 Checkbutton 时可同时设置 onvalue 和 offvalue 选项为打开和关闭分别指定值。如果不指定 onvalue 和 offvalue,则 onvalue 默认为1,offvalue 默认为 0。下面代码使用两组 Checkbutton 示例 Checkbutton 的用法。
from tkinter import * from tkinter import ttk from tkinter import messagebox class App: def __init__(self, master): self.master = master self.initWidgets() def initWidgets(self): # 创建一个 Label 组件 ttk.Label(self.master, text=\'选择你喜欢的人物:\').\\ pack(fill=BOTH, expand=YES) self.chars = [] # 定义元组 characters = (\'赵子龙\', \'关羽\', \'张飞\', \'曹操\') # 采用循环创建多个 Checkbutton for each in characters: intVar = IntVar() self.chars.append(intVar) cb = ttk.Checkbutton(self.master, text=each, variable=intVar, # 将Checkbutton绑定到intVar变量 command=self.change) # 将选中事件绑定到 self.change 方法 cb.pack(anchor=W) # 创建一个 Label 组件 ttk.Label(self.master, text=\'选择你喜欢的图书:\').\\ pack(fill=BOTH, expand=YES) # ------------- 下面是第组 Checkbutton --------------- self.books = [] # 定义两个元组 books = (\'Python 基础入门\', \'Linux 服务器搭建篇\', \'Java 编程思想\', \'JavaScript 精通\') vals = (\'python\', \'linux\', \'java\', \'javascript\') i = 0 # 采用循环创建多个 Checkbutton for book in books: strVar = StringVar() self.books.append(strVar) cb = ttk.Checkbutton(self.master, text=book, variable=strVar, # 将 Checkbutton 绑定到 strVar 变量 onvalue=vals[i], offvalue=\'无\', command=self.books_change) # 将选中事件绑定到 books_change 方法 cb.pack(anchor=W) i += 1 def change(self): # 将 self.chars 列表转换成元素为 str 的列表 new_li = [str(e.get()) for e in self.chars] # 将 new_li 列表连接成字符串 st = \', \'.join(new_li) messagebox.showinfo(title=None, message=st) def books_change(self): # 将 self.books 列表转换成元素为 str 的列表 new_li = [e.get() for e in self.books] # 将 new_li 列表连接成字符串 st = \', \'.join(new_li) messagebox.showinfo(title=None, message=st) root = Tk() root.title("Checkbutton 测试") # 改变窗口图标 root.iconbitmap(\'images/logo.ico\') App(root) root.mainloop()
上面代码中第21~24行创建的第一组 Checkbutton 没有指定 onvalue 和 offvalue,因此 onvalue 和 offvalue 默认分别是1、0,所以将这组 Checkbutton 绑定到 IntVar 类型的变量;第39~44行代码为第二组 Checkbutton 的 onvalue 和 offvalue 都指定为字符串,因此将这组 Checkbutton 绑定到 StringVar 类型的变量。运行这段代码,选中部分选项后可以看到如图二十所示的效果。
图二十 Checkbutton组件
6、 Listbox 和 Combobox 组件
Listbox 是一个列表框,通过列表框可选择一个列表项。ttk 下的 Combobox 是 Listbox 的改进版,不仅支持单行文本输入,还提供下拉列表框供选择,因此称为复合框。
要创建 Listbox 需要经过两步:
(1)、创建 Listbox 对象,并且添加各种执行选项。该对象除了支持 GUI 的大部分通用选项外,还支持 selectmode 选项,用于设置 Listbox 的选择模式。
(2)、调用 Listbox 的 insert(self, index, *elements) 方法来添加选项。该方法的最后一个参数是可变长度的参数,所以一次可以添加一个选项,也可传入多个参数来添加多个选项。index 参数是指定插入位置,支持 END(结尾处)、ANCHOR(当前位置)和 ACTIVE(选中处)等特殊索引。
其中 Listbox 的 selectmode 支持的选择模式有如下几种:
(1)、\'browse\':单选模式,支持按住鼠标键拖动来改变选择。
(2)、\'multiple\':多选模式。
(3)、\'single\':单选模式,必须通过鼠标键单击来改变选择。
(4)、\'extended\':扩展的多选模式,必须通过 Ctrl 或 Shift 键辅助实现多选。
Listbox 的基本用法示例如下:
from tkinter import * from tkinter import ttk class App: def __init__(self, master): self.master = master self.initWidgets() def initWidgets(self): topF = Frame(self.master) topF.pack(fill=Y, expand=YES) # 创建 Listbox 组件 self.lb = Listbox(topF) self.lb.pack(side=LEFT, fill=Y, expand=YES) for item in [\'Python\', \'Linux\', \'HTML\', \'Java\']: self.lb.insert(END, item) # 也可直接插入多个选项 self.lb.insert(ANCHOR, \'Python\', \'Linux\', \'HTML\', \'Java\') # 创建 Scrollbar 组件,设置该组件与 self.lb 的垂直滚动关联 scroll = Scrollbar(topF, command=self.lb.yview) scroll.pack(side=RIGHT, fill=Y) # 设置 self.lb 的垂直滚动影响 scroll 滚动条 self.lb.configure(yscrollcommand=scroll.set) f = Frame(self.master) f.pack() Label(f, text=\'选择模式:\').pack(side=LEFT) modes = (\'multiple\', \'browse\', \'single\',\'extended\') self.strVar = StringVar() for m in modes: rb = ttk.Radiobutton(f, text=m, value=m, variable=self.strVar, command=self.choose_mode) rb.pack(side=LEFT) self.strVar.set(\'browse\') def choose_mode(self): print(self.strVar.get()) self.lb[\'selectmode\'] = self.strVar.get() root = Tk() root.title(\'Listbox 测试\') # 改变窗口图标 root.iconbitmap(\'images/logo.ico\') App(root) root.mainloop()
上面代码中第15、16行使用循环来插入多个选项;第18行直接插入多个选项。第37行代码根据用户选择来改变 Listbox 的 selectmode 选项,这样可看到 Listbox 不同选项的差异。运行这段代码,可以看到图二十一所示的界面。
图二十一 Listbox 的运行效果
Listbox 除了 insert() 方法外,还支持操作列表项的方法:
(1)、selection_set(self,first,last=None):选中从first到last(包含)的所有列表项。不指定last,则直接选中first列表项。
(2)、selection_clear(self, first, last=None):取消选中从first到last的所有列表项。不指定last则只取消选中first列表项。
(3)、delete(self,first,last=None):删除从first到last的所有列表项。不指定last则只删除first列表项。
Listbox 使用 listvariable 选项与变量进行绑定,用于控制 Listbox 包含哪些项。如果使用 listvariable 选项与变量进行了双向绑定,则无须调用 insert()、delete()方法添加、删除列表项,只要通过绑定变量即可改变 Listbox 中的列表项。关于操作Listbox 中选项的方法如下所示:
from tkinter import * from tkinter import ttk class App: def __init__(self, master): self.master = master self.initWidgets() def initWidgets(self): topF = Frame(self.master) topF.pack(fill=Y, expand=YES) # 定义 StringVar 变量 self.v = StringVar() # 创建 Listbox 组件, 与 v 变量绑定 self.lb = Listbox(topF, listvariable=self.v) self.lb.pack(side=LEFT, fill=Y, expand=YES) for item in range(20): self.lb.insert(END, str(item)) # 创建 Scrollbar 组件,设置组件与 self.lb 的垂直滚动关联 scroll = Scrollbar(topF, command=self.lb.yview) scroll.pack(side=RIGHT, fill=Y) # 设置 self.lb 的垂直滚动影响 scroll 滚动条 self.lb.configure(yscrollcommand=scroll.set) f = Frame(self.master) f.pack() Button(f, text=\'选中10项\', command=self.select).pack(side=LEFT) Button(f, text=\'清除选中3项\', command=self.clear_select).pack(side=LEFT) Button(f, text=\'删除3项\', command=self.delete).pack(side=LEFT) Button(f, text=\'绑定变量\', command=self.var_select).pack(side=LEFT) def select(self): # 选中指定项 self.lb.selection_set(0, 9) def clear_select(self): # 取消选中指定项 self.lb.selection_clear(1, 3) def delete(self): # 删除指定项 self.lb.delete(5, 8) def var_select(self): # 修改与 Listbox 绑定的变量 self.v.set((\'12\', \'15\')) root = Tk() root.title(\'Listbox测试\') # 改变窗口图标 root.iconbitmap(\'images/logo.ico\') App(root) root.mainloop()
上面代码中第33行控制选中列表项中第一个到第十选项;第36行控制取消选中列表项中的3项;第39行控制删除列表项的4项;第42行代码通过绑定变量来改变 Listbox 中的列表项。运行这段代码,删除其中5~8的4项后的运行效果如图二十二所示。
图二十二 操作列表项
Listbox 的 curselection() 方法可获取当前选中的项,该方法返回一个包含当前 Listbox 的所有选中的项。
Listbox 不能使用 command 选项来绑定事件处理函数或方法,但是可以通过 bind() 方法来实现。示例代码如下:
from tkinter import * from tkinter import ttk class App: def __init__(self, master): self.master = master self.initWidgets() def initWidgets(self): topF = Frame(self.master) topF.pack(fill=Y, expand=YES) # 定义 StringVar 变量 self.v = StringVar() # 创建 Listbox 组件, 与 v 变量绑定 self.lb = Listbox(topF, listvariable=self.v) self.lb.pack(side=LEFT, fill=Y, expand=YES) for item in range(20): self.lb.insert(END, str(item)) # 创建 Scrollbar 组件,设置组件与 self.lb 的垂直滚动关联 scroll = Scrollbar(topF, command=self.lb.yview) scroll.pack(side=RIGHT, fill=Y) # 设置 self.lb 的垂直滚动影响 scroll 滚动条 self.lb.configure(yscrollcommand=scroll.set) # 为双击事件绑定事件处理方法 self.lb.bind("<Double-1>", self.click) def click(self, event): from tkinter import messagebox # 获取 Listbox 当前选中项 messagebox.showinfo(title=None, message=str(self.lb.curselection())) root = Tk() root.title(\'Listbox测试\') # 改变窗口图标 root.iconbitmap(\'images/logo.ico\') App(root) root.mainloop()
上面代码中第25行为 Listbox 的左键双击事件()绑定了事件处理方法;当双击 Listbox时,就会触发该对象的 click 方法;第30行代码则调用了 Listbox 的 curselection() 方法来获取当前选中项。运行这段代码,双击某个列表项,可看到如图二十三所示的界面。
图二十三 为双击事件绑定事件处理方法
Combobox 的用法很简单,支持的选项如下:
(1)、values选项:用于设置多个选项,例如值可以是列表或元素等。
(2)、state选项:支持 \'readonly\' 状态,表示 Combobox 的文本框不允许编辑,只能通过下拉列表框的列表项来改变。
(3)、textvariable选项:可与指定变量绑定后,通过该变量来获取或修改 Combobox 组件的值。
(4)、postcommand选项:用于指定事件处理函数或方法;当单击 Combobox 的下拉箭头时,就会触发 postcommand 选项指定的事件处理函数或方法。
关于 Combobox 组件的用法示例如下:
from tkinter import * from tkinter import ttk class App: def __init__(self, master): self.master = master self.initWidgets() def initWidgets(self): self.strVar = StringVar() # 创建 Combobox 组件 self.cb = ttk.Combobox(self.master, textvariable=self.strVar, # 绑定到 self.strVar 变量 postcommand=self.choose) # 当用户单击下拉箭头时触发 self.choose 方法 self.cb.pack(side=TOP) # 为 Combobox 配置多个选项 self.cb[\'values\'] = (\'Python\', \'HTML\', \'Linux\', \'Java\') f = Frame(self.master) f.pack() self.isreadonly = IntVar() # 创建 Checkbutton,绑定到 self.isreadonly 变量 Checkbutton(f, text=\'是否只读:\', variable=self.isreadonly, command=self.change).pack(side=LEFT) # 创建 Button,单击该按钮时触发 setvalue 方法 Button(f, text=\'绑定变量设置\', command=self.setvalue).pack(side=LEFT) def choose(self): from tkinter import messagebox # 获取 Combobox 的当前值 messagebox.showinfo(title=None, message=str(self.cb.get())) def change(self): self.cb[\'state\'] = \'readonly\' if self.isreadonly.get() else \'enable\' def setvalue(self): self.strVar.set(\'人生苦短,我用Python\') root = Tk() root.title(\'Combobox测试\') # 改变窗口图标 root.iconbitmap(\'images/logo.ico\') App(root) root.mainloop()
上面代码的第13行将 Combobox 组件绑定到 self.strVar 变量;第14行代码为 Combobox 的 command 绑定事件处理方法。第34行代码根据列表的值来确定 Combobox 是否允许编辑。运行这段代码,可看到图二十四所示的界面。
图二十四 Combobox 组件
7、 Spinbox 组件
该组件是有两个小箭头文本框,两个小箭头可上下调整该组件内的值,也可在文本框内输入内容作为该组件的值。
Spinbox 本质是一个列表框,类似于 Combobox,但 Spinbox 不会展开下拉列表供选择,只能用上下小箭头选择不同的项。
Spinbox 的选项列表:可通过from(由于是关键字,要写成from_)、to、increment选项来指定选项列表,也可通过 values 选项来指定多个列表项,该选项的值可以是 list 或 tuple。
Spinbox 的 textvariable 选项与指定变量绑定时,可通过该变量来获取或修改 Spinbox 组件的值。
Spinbox 的 command 选项用于指定事件处理函数或方法;当点击 Spinbox 的向上、向下箭头时,就会触发 command 选项指定的事件处理函数或方法。
Spinbox 的用法示例如下所示:
from tkinter import * from tkinter import ttk class App: def __init__(self, master): self.master = master self.initWidgets() def initWidgets(self): ttk.Label(self.master, text=\'指定from、to、increment\').pack() #通过指定 from、to、increament 选项创建 Spinbox sb1 = Spinbox(self.master, from_=20, to=100, increment=5) sb1.pack(fill=X, expand=YES) ttk.Label(self.master, text=\'指定values\').pack() # 通过指定values 选项创建 Spinbox self.sb2 = Spinbox(self.master, values=(\'Python\', \'HTML\', \'Linux\', \'Java\'), command=self.press) # 通过 command 绑定事件处理方法 self.sb2.pack(fill=X, expand=YES) ttk.Label(self.master, text=\'绑定变量\').pack() self.intVar = IntVar() # 通过指定 values 选项创建 Spinbox,并为之绑定变量 sb3 = Spinbox(self.master, values=list(range(20, 100, 4)), textvariable=self.intVar, # 绑定变量 command=self.press) sb3.pack(fill=X, expand=YES) self.intVar.set(33) # 通过变量愀 Spinbox 的值 def press(self): print(self.sb2.get()) root = Tk() root.title(\'Combobox测试\') # 改变窗口图标 root.iconbitmap(\'images/logo.ico\') App(root) root.mainloop()
上面代码中第12~13行代码使用 from_、to、increment 选项创建了 Spinbox 组件;第17~19代码使用 values 选项创建了 Spinbox 组件,并为该组件的 command 选项指定了事件处理方法,在点击 Spinbox 组件的上下箭头调整值时,该选项指定的事件处理方法就会被触发;第24~27行代码在创建 Spinbox 时使用 textvariable 选项绑定变量,这样在程序中完全可通过绑定变量来访或修改 Spinbox 组件的值。运行这段代码,可看到如图二十五所示的界面。
图二十五 Spinbox组件
8、 Scale 和 LabeledScale 组件
Scale 组件是一个滑动条,可为滑动条设置最小值和最大值,也可设置滑动条每次调节的步长。支持的选项有下面这些:
(1)、from:设置最小值;
(2)、to:设置最大值;
(3)、resolution:设置滑动时的步长。
(4)、label:为 Scale 组件设置标签内容。
(5)、length:设置轨道的长度。
(6)、width:设置轨道的宽度。
(7)、troughcolor:设置轨道的背景色。
(8)、sliderlength:设置尚志的长度。
(9)、sliderrelief:设置滑块的立体样式。
(10)、showvalue:设置是否显示当前值。
(11)、orient:设置方向,该选项支持 VERTICAL 和 HORIZONTAL 两个值。
(12)、digits:设置有效数字至少要有几位。
(13)、variable:用于与变量进行绑定。
(14)、command:为 Scale 组件绑定事件处理函数或方法。
注意:ttk.Scale 的组件更接近操作系统本地的效果,但可支持的选项少。
关于 Scale 组件的功能选项和用法示例如下:
from tkinter import * from tkinter import ttk class App: def __init__(self, master): self.master = master self.initWidgets() def initWidgets(self): self.scale = Scale(self.master, from_=-100, # 设置最小值 to=100, # 设置最大值 resolution=5, # 设置步长 label=\'Scale 示例\', # 设置标签内容 length=400, # 设置轨道的长度 width=30, # 设置轨道的宽度 troughcolor=\'lightblue\', # 设置轨道的背景色 sliderlength=20, # 设置滑块的长度 sliderrelief=SUNKEN, # 设置滑块的立体样式 showvalue=YES, # 设置显示当前值 orient=HORIZONTAL # 设置水平方向 ) self.scale.pack() # 创建一个 Frame 作为容器 f = Frame(self.master) f.pack(fill=X, expand=YES, padx=10) Label(f, text=\'是否显示值:\').pack(side=LEFT) i = 0 self.showVar = IntVar() self.showVar.set(1) # 创建两个 Radiobutton 控制 scale 是否显示值 for s in (\'不显示\', \'显示\'): Radiobutton(f, text=s, value=i, variable=self.showVar, command=self.switch_show).pack(side=LEFT) i += 1 # 创建一个 Frame 作为容器 f2 = Frame(self.master) f2.pack(fill=X, expand=YES, padx=10) Label(f2, text=\'方向:\').pack(side=LEFT) j = 0 self.orientVar = IntVar() self.orientVar.set(0) # 创建两个 Radiobutton 控制 Scale 的方向 for s in (\'水平\', \'垂直\'): Radiobutton(f2, text=s, value=j, variable=self.orientVar, command=self.switch_orient).pack(side=LEFT) j += 1 def switch_show(self): self.scale[\'showvalue\'] = self.showVar.get() def switch_orient(self): # 根据单选钮的选中状态设置 orient 选项的值 self.scale[\'orient\'] = VERTICAL if self.orientVar.get() else HORIZONTAL root = Tk() root.title(\'Scale 测试\') App(root) root.mainloop()
上面代码中第10~22行创建了 Scale 组件,并且为该组件指定前面介绍的多个选项。第50行代码根据单选钮的选中状态来设置 Scale 组件的 showvalue 选项,该选项会控制 Scale 组件是否显示当前值;第53行代码根据单选钮的选中状态设置 Scale 是水平的还是垂直的,通过改变 orient 选项值为设置。代码运行效果如图二十六所示。
图二十六 Scale组件运行效果
Scale 也支持 variable 进行变量绑定,也支持使用 command 选项绑定事件处理函数或方法,这样在点击滑动条的滑块时,就会触发 command 绑定的事件处理方法,Scale 的事件处理方法还可能额外定义一个参数,用于获取 Scale 的当前值。示例如下:
from tkinter import * from tkinter import ttk class App: def __init__(self, master): self.master = master self.initWidgets() def initWidgets(self): # 定义变量 self.doubleVar = DoubleVar() self.scale = Scale(self.master, from_=-100, # 设置最小值 to=100, # 设置最大值 resolution=5, # 设置步长 label=\'Scale 示例\', # 设置标签内容 length=300, # 设置轨道的长度 width=15, # 设置轨道的宽度 orient=HORIZONTAL, # 设置水平方向 digits=10, # 设置10位有效数字 command=self.change, # 绑定事件处理方法 variable=self.doubleVar # 绑定变量 ) self.scale.pack() # 设置 Scalie 的当前值 self.scale.set(20) # Scale 的事件处理方法可以接收到 Scale 的值 def change(self, value): print(value, self.scale.get(), self.doubleVar.get()) root = Tk() root.title(\'Scale 测试\') App(root) root.mainloop()
上面代码中,第29行使用了三种方式来获取 Scale 组件的值。分别是:
(1)、通过事件处理方法的参数来获取。
(2)、通过 Scale 组件提供的 get() 方法来获取。
(3)、通过 Scale 组件绑定的变量来获取。
这三种方式获取到的变量值都是一样的,但是 Scale 组件的 digits 选项为10,表示有效数字保留10位,所以在通过事件处理方法获取的值会有 10 位有效数字,如:-10.0000000。
ttk.LabeledScale 是平台化的滑动条,允许设置的选项少,可设置 from、to、compound 等几项,生成一是一个水平滑动条(不能变成垂直的),compound 用于控制滑动条的数值标签是显示在滑动条上方或下方。示例代码如下:
from tkinter import * from tkinter import ttk class App: def __init__(self, master): self.master = master self.initWidgets() def initWidgets(self): self.scale = ttk.LabeledScale(self.master, from_=-100, # 设置最小值 to=100, # 设置最大值 compound=BOTTOM # 设置显示数值的标签在下方 ) self.scale.value = -20 self.scale.pack(fill=X, expand=YES) root = Tk() root.title(\'LabeledScale 测试\') App(root) root.mainloop()
上面代码中第10~14行创建了一个 LabeledScale 组件,该组件生成一个水平滑动条,默认数值标签显示在滑动条上方,通过compound 选项设置为BOTTOM,让数值标签显示在滑动条的下方。
9、Labelframe 组件
Labelframe 是 Frame 容器的改进版,它允许为容器添加一个标签,该标签可以是普通的文字,也可以是任意的GUI组件。
ttk.Labelframe 与 ttk.LabelFrame(注意 f 大小写)是完全相同的,出现两上是因为与 tkinter.LabelFrame 保持名字上的兼容。
Labelframe 要设置文字标签,只要为它指定 text 选项即可。关于 Labelframe 组件的用法示例如下:
from tkinter import * from tkinter import ttk class App: def __init__(self, master): self.master = master self.initWidgets() def initWidgets(self): # 创建 Labelframe 容器 lf = ttk.Labelframe(self.master, text="请选择图书", padding=20) lf.pack(fill=BOTH, expand=YES, padx=10, pady=10) books = [\'Python\', \'HTML\', \'Linux\', \'Java\'] i = 0 self.intVar = IntVar() # 使用循环创建多个 Radiobutton ,并放入 Labelframe 中 for book in books: Radiobutton(lf, text=\'高级\' + book + \'编程\', value=i, variable=self.intVar, command=self.click).pack(side=LEFT) i += 1 def click(self): print(self.intVar.get()) root = Tk() root.title(\'Labelframe 测试\') # 改变窗口图标 root.iconbitmap(\'images/logo.ico\') App(root) root.mainloop()
上面代码第11行创建一个 Labelframe 组件,并指定了 text 选项,该选项会作为容器的标签。接下来向 Labelframe 容器中添加4个 Radibutton。运行这段代码可看到如图二十七所示的界面。
图二十七 Labelframe组件
Labelframe 对标签定制的选项有:
(1)、labelwidget:设置任意GUI组件作为标签。
(2)、labelanchor:设置标签的位置。选项值是有12个,分别有用于控制标签位置。这12个选项如下:\'e\', \'s\', \'w\', \'n\', \'es\', \'ws\', \'en\', \'wn\', \'ne\', \'nw\', \'se\', \'sw\'。
对 Labelframe 标签进行定制的代码如下:
from tkinter import * from tkinter import ttk class App: def __init__(self, master): self.master = master self.initWidgets() def initWidgets(self): # 创建 Labelframe 容器 self.lf = ttk.Labelframe(self.master, padding=20) self.lf.pack(fill=BOTH, expand=YES, padx=10, pady=10) # 创建一个显示图片的 Label bm = PhotoImage(file=\'images/z.png\') lb = Label(self.lf, image=bm) lb.bm = bm # 将 Labelframe 的标题设为显示图片的 Label self.lf[\'labelwidget\'] = lb # 定义代表 Labelframe 的标题位置的 12 个常量 self.books = [\'e\', \'s\', \'w\', \'n\', \'es\', \'ws\', \'en\', \'wn\', \'ne\', \'nw\', \'se\', \'sw\'] i = 0 self.intVar = IntVar() # 使用循环创建多个 Radiobutton,并放入 Labelframe 中 for book in self.books: Radiobutton(self.lf, text=book, value=i, command=self.change, variable=self.intVar).pack(side=LEFT) i += 1 self.intVar.set(9) def change(self): # 通过 labelanchor 选项改变 Labelframe 的标签的位置 self.lf[\'labelanchor\'] = self.books[self.intVar.get()] root = Tk() root.title(\'Labelframe 测试\') # 改变窗口图标 root.iconbitmap(\'images/logo.ico\') App(root) root.mainloop()
上面代码中第18行通过 labelwidget 选项定制了该 labelframe 的标签,选项值是图片的 Label,因此该 Labelframe 的标签就是一张图片。第32行代码根据单选钮的选中状态来调整 Labelframe 的标签位置。这段代码的运行效果如图二十八所示。
图二十八 定制Labelframe的标签
10、 Panedwindow 组件
Panedwindow 是一个管理窗口布局的容器,可添加多个子组件(不需要 pack、grid、place布局),为每个子组件划分一个区域,用户可用鼠标移动各区域的分隔线来改变各子组件的大小(不指定大小,则默认占满整个区域)。
ttk组件下的 ttk.Panedwindow 与 ttk.PanedWindow 功能是完全一样的,主要是为了与 tkinter.PanedWindow 兼容。
Panedwindow 是一个有特色的容器,自带布局,可通过 orient 选项指定水平或垂直方向,让容器中的各组件按水平或垂直排列。
在创建 Panedwindow 容器后,可操作子组件的方法有下面几个:
(1)、
add(self, child, **kw)
:添加一个子组件。 (2)、insert(self, pos, child, **kw)
:在 pos 位置插入一个子组件。 (3)、remove(self, child):删除一个子组件,该子组件所在区域也被删除。
关于 Panedwindow 的添加、插入、删除子组件的示例如下所示:
from tkinter import * from tkinter import ttk class App: def __init__(self, master): self.master = master self.initWidgets() def initWidgets(self): # 创建 Style style = ttk.Style() style.configure("Py.TPanedwindow", background=\'darkgray\', relief=RAISED) # 创建 Panedwindow 组件,通过 Style 属性设置分隔线 pwindow = ttk.PanedWindow(self.master, orient=VERTICAL, style="Py.TPanedwindow") pwindow.pack(fill=BOTH, expand=1) first = ttk.Label(pwindow, text=\'第一个标签\') # 调用 add 方法添加组件,每个组件占一个区域 pwindow.add(first) okBn = ttk.Button(pwindow, text="第二个按钮", # 调用 remove() 方法删除组件,该组件所在区域消失 command=lambda : pwindow.remove(okBn)) # 调用 add 方法添加组件,每个组件占一个区域 pwindow.add(okBn) entry = ttk.Entry(pwindow, width=30) # 调用 add 方法添加组件,每个组件占一个区域 pwindow.add(entry) # 调用 insert 方法插入组件 pwindow.insert(1, Label(pwindow, text=\'插入的标签\')) root = Tk() root.title(\'Labelframe 测试\') # 改变窗口图标 root.iconbitmap(\'images/logo.ico\') App(root) root.mainloop()
上面代码中第11、12行创建了 ttk.Style 对象,该对象用于管理 ttk 组件的样式,这样 ttk 组件可通过 style 选项复用 ttk.Style 管理的样式。这里使用 ttk.Style 为 ttk.Panedwindow 指定样式后才能看到 ttk.Panedwindow 容器内的分隔线(默认看不见)。
第19行代码调用 add() 方法为 Panedwindow 容器添加子组件;第22行代码调用了 remove() 方法删除 Panedwindow 容器中的子组件;第29行代码调用了 insert() 方法向 Panedwindow 容器中添加了子组件。
运行上面这段代码会看到如图二十九所示的界面。在图二十九中单击【1图】的【第二个按钮】将会删除 Panedwindow 组件中的该按钮,该按钮所占的区域也随之消失,此时会看到【2图】所示的界面。
图二十九 Panedwindow 组件示例
Panedwindow 组件只能水平和垂直排列,显得有些局限。但是 Panedwindow 组件是可以嵌套的,可以实现功能丰富的界面。下面代码在水平 Panedwindow 中嵌套垂直 Panedwindow。
from tkinter import * from tkinter import ttk class App: def __init__(self, master): self.master = master self.initWidgets() def initWidgets(self): # 创建 Style style = ttk.Style() style.configure("Py.TPanedwindow", background=\'red\', relief=RAISED) # 创建第一个 Panedwindow 组件,通过 style 属性设置分隔线 pwindow = ttk.PanedWindow(self.master, orient=HORIZONTAL, style="Py.TPanedwindow") pwindow.pack(fill=BOTH, expand=YES) left = ttk.Label(pwindow, text="左边标签", background=\'pink\') pwindow.add(left) # 创建第二个 Panedwindow 组件,该组件的方向是垂直的 rightwindow = PanedWindow(pwindow, orient=VERTICAL) pwindow.add(rightwindow) top = Label(rightwindow, text=\'右上标签\', background=\'lightgreen\') rightwindow.add(top) bottom = Label(rightwindow, text="右下标签", background=\'lightblue\') rightwindow.add(bottom) root = Tk() root.title(\'Panedwindow 测试\') # 改变窗口图标 root.iconbitmap(\'images/logo.ico\') App(root) root.mainloop()
上面代码中第14、15行创建了一个水平分布的 Panedwindow 容器,在该容器中先添加一个 Label 组件;第20行代码创建一个垂直分布的 Panedwindow容器,该容器被添加到第一个 Panedwindow 容器中,这样就形成了嵌套,从而实现功能更丰富的界面。运行结果界面如图三十所示。
图三十 Panedwindow嵌套
11、OptionMenu 组件
该组件可构建一个带菜单的按钮,该菜单可在按钮的四个方向上展开,展开方向可通过 direction 选项控制。要使用 OptionMenu,只要调用它的如下构造函数即可: __init__(self, master, variale, value, *values, **kwargs)
其中,master 参数的作用与 Tkinter 组件一样,指定将该组件放入哪个容器中。其它参数含义如下:
(1)、variable:指定该按钮上的菜单与哪个变量绑定。
(2)、value:指定默认选择菜单中的哪一项。
(3)、values:Tkinter 将收集为此参数传入的多个值,为每个值创建一个菜单项。
(4)、kwargs:用于为 OptionMenu 配置选项。除了前面几个选项外,还可通过 direction 选项控制菜单的展开方向。
关于 OptionMenu 的示例如下,示例中通过单选钮控制 OptionMenu 中菜单的展开方向。
from tkinter import * from tkinter import ttk class App: def __init__(self, master): self.master = master self.initWidgets() def initWidgets(self): self.sv = StringVar() # 创建一个 OptionMenu 组件 self.om = ttk.OptionMenu(self.master, self.sv, # 绑定变量 \'Python\', # 设置初始选中值 \'Kotlin\', # 以下多个值用于设置菜单项 \'HTML\', \'Linux\', \'Java\', \'Python\', \'JavaScript\', command=self.print_option) # 绑定事件处理方法 self.om.pack() # 创建 Labelframe 容器 lf = ttk.Labelframe(self.master, padding=20, text=\'请选择菜单方向\') lf.pack(fill=BOTH, expand=YES, padx=10, pady=10) # 定义代表 Labelframe 的标签位置的 12 个常量 self.directions = [\'below\', \'above\', \'left\', \'right\', \'flush\'] i = 0 self.intVar = IntVar() # 使用循环创建多个 Radiobutton,并放入 Labelframe 中 for direct in self.directions: Radiobutton(lf, text=direct, value=i, command=self.change, variable=self.intVar).pack(side=LEFT) i += 1 self.intVar.set(9) def print_option(self, val): # 通过两个各方来获取 OptionMenu 选中的菜单项的值 print(self.sv.get(), val) def change(self): # 通过 direction 选项改变 OptionMenu 中菜单的展开方向 self.om[\'direction\'] = self.directions[self.intVar.get()] root = Tk() root.title(\'OptionMenu 测试\') # 改变窗口图标 root.iconbitmap(\'images/logo.ico\') App(root) root.mainloop()
上面代码
以上是关于part11-2 Python图形界面编程(Tkinter常用组件对话框(Dialog)菜单Canvas绘图)的主要内容,如果未能解决你的问题,请参考以下文章