3.6 tkinter 之设计友好的界面

如果创建大型用户界面,则需要找到一种不会使用户因复杂的布局而不知所措的方法。

用户界面可以从许多不同的模块中组合起来,从多个画布(canvas)小部件和深度嵌套框架(frame)构建,但这并不意味着用户认为它很复杂。设计一个友好的界面应该从用户的角度出发,切记让用户感到困扰。

1 多个窗口

在应用程序中使用多个窗口的好处之一是简化用户界面,要求用户一次只关注一个窗口的内容(要求他们同时关注或切换多个窗口也可以产生相反的效果)。同样,仅显示与当前任务相关的小部件(通过网格(grid))有助于简化用户界面。

如果你确实需要同时在屏幕上显示大量的小部件,你必须考虑如何直观地组织它们。除了使用网格(grid)使小部件彼此对齐变得容易,还可以使用另一个有用的辅助工具 空白 (White space)。将相关小部件彼此非常接近(可能立即使用上面的解释性标签),并用空白与其他不太相关的小部件分开,有助于用户自行组织用户界面。

3 ttk.Separator:分隔

比使用空白更节省空间的分组小部件的第二种方法是在小部件组之间放置一个细的水平或垂直分隔线。为此,Tk 提供了一个非常简单的分隔小部件。

Separator 是使用 ttk.Separator 创建的:

s = ttk.Separator(parent, orient="vertical")

这里 "orient" 可指定 "horizontal" 或者 "vertical"。

root = Tk()
lb = ttk.Label(root, text="分隔条")
sep = ttk.Separator(root, orient="horizontal")
lb1 = ttk.Label(root, text="注释")
entry = ttk.Entry(root)
lb.grid()
sep.grid(sticky='we')
lb1.grid()
entry.grid()
root.mainloop()

4 Label Frames:标签框架

标签框小部件(也称为组框,group box)提供了另一种对相关组件进行分组的方法。它的作用类似于一个普通的 ttk::frame,因为你通常会使用它作为一个容纳其他小部件的容器。但是,它以直观方式地将其与用户界面的其余部分分开显示。您可以为其选择提供要显示在标签框外的文本标签。

使用 ttk.Labelframe 创建:

lf = ttk.Labelframe(parent, text='Label')

看一个例子:

root = Tk()
root['background'] = 'blue'
lf = ttk.Labelframe(root,
                    text='外部标签')
lb = ttk.Label(lf, text='内部')
lb_outer = ttk.Label(root, text='外部', foreground='red')
lb.grid()
lf.grid(sticky='ns', columnspan=2)
lb_outer.grid(ipady=2)
root.mainloop()

5 Paned Windows:窗格视窗

窗格视窗(panedwindow)小部件允许您在彼此(或左右)上下堆叠两个或多个可调整大小的小部件。用户可以通过拖动位于它们之间的窗框来调整每个窗格的相对高度(或宽度)。通常,要添加到窗格视窗的小部件将是包含许多其他小部件的框架。

窗格视窗 是使用 ttk.Panedwindow 创建的:

p = ttk.Panedwindow(parent, orient="vertical")
# 创建两个窗格
f1 = ttk.Labelframe(p, text='Pane1', width=100, height=100)
f2 = ttk.Labelframe(p, text='Pane2', width=100, height=100)  
# 添加到主窗格
p.add(f1)
p.add(f2)

窗格视窗可以是 "vertical"(其窗格垂直堆叠在一起),或 "horizontal"。重要的是,添加到窗格窗口中的所有窗格必须是窗格视窗本身的直接子级。调用 "add" 方法将在窗格列表的末尾添加新窗格。"insert position subwindow" 方法允许您将窗格放置在窗格列表中的给定位置(0..n-1);如果窗格已由窗格视窗管理,它将移动其到新位置。您可以使用 "forget subwindow" 从窗格中删除窗格;还可以传递一个位置而不是子窗口。

其他选项允许您为每个窗格分配相对权重,以便如果整个窗格调整大小,某些窗格将获得比其他窗格更多的空间。此外,您还可以在平移窗口中调整每个窗框之间的每个窗框的位置。有关详细信息,请参阅命令引用

下面看几个例子。

5.1 添加窗格

使用 eval('ttk.'+widget) 命令可以直接调用指定的模块,具体的代码:

root = Tk()
panes = ttk.PanedWindow(orient='vertical')
panes.pack(fill='both', expand=1)
for widget in ['Label', 'Button', 'Checkbutton', 'Radiobutton']:
    panes.add(eval('ttk.'+widget)(panes, text='欢迎'))
root.mainloop()
ws = []
for name in ['Label', 'Button', 'Checkbutton', 'Radiobutton']:
    ws.append(eval('ttk.'+name)(panes, text='欢迎'))
for widget in ws:
    panes.add(widget)
panes.forget(ws[-1]) # 删除最后一个 pane,也可以使用 remove 方法
root.mainloop()

5.3 插入新的位置的 pane

root = Tk()
panes = ttk.PanedWindow(orient='vertical')
panes.pack(fill='both', expand=1)
ws = []
for name in ['Label', 'Button', 'Checkbutton', 'Radiobutton']:
    ws.append(eval('ttk.'+name)(panes, text='欢迎'))
for widget in ws:
    panes.add(widget)
# 在首位插入新的 pane
panes.insert(0, ttk.Label(panes, text='世界'))
root.mainloop()

6 Notebook:笔记本

笔记本小部件使用选项卡式笔记本的比喻,让用户使用索引选项卡在多个页面之间切换。使用 ttk.Notebook 便可创建:

n = ttk.Notebook(parent)
# first page, which would get widgets gridded into it
f1 = ttk.Frame(n)   
f2 = ttk.Frame(n)   # second page
n.add(f1, text='One')
n.add(f2, text='Two')

选项卡式笔记本上的操作与窗格窗口上的操作类似。每个页面通常是一个框架,也是笔记本本身的直接子级(子窗口)。新页面及其关联的选项卡将添加到选项卡列表的末尾,方法是 "add subwindow ?option value...?"。"text" 选项卡选项用于设置选项卡上的标签;"state" 选项卡选项也很有用,它可以具有值 "normal", "disabled" (不可选择), 或 "hidden"。