### 8.2.4 布局
布局指的是界面元素在界面中的位置安排。Tkinter 中提供了布局管理器,其任务是根据 程序员的要求以及其他一些约束来安排构件的位置。使用布局管理器的优点是程序员不需要 了解底层显示系统的细节,可以在较高层次上考虑界面布局问题。
如前所述,多数构件在创建之后还需进行布局才会显示在屏幕上,即要经过两个步骤:
```
w = Constructor(parent,...) w.GeometryManager(...)
```
其中 Constructor 是构件类(如 Label,Button 等),parent 是父构件,GeometryManager 是布局管理器方法。Tkinter 提供了三种布局管理器:Pack、Grid 和 Place。
Pack 布局管理器
Pack 布局管理器以紧凑的方式将构件在窗口中“打包”,调用构件的 pack 方法即可以这 种方式布局。具体的打包方式可以用一个比方来说明:设想窗口是由弹性材料制成的,当要 放入一个构件时,就先把窗口空间撑大到足够容纳该构件,然后将构件紧贴内部的某条边(缺 省是顶边)放入,然后重复此过程不断放入构件。可见,在缺省情形下,放入同一个窗口的 所有构件是沿垂直方向自顶向下一个紧贴一个进行布置的,但可以通过 pack 方法的 side 选项 设置成沿水平方向打包。
例如,执行下列语句后得到的布局效果如图 8.16(a)所示。
```
>>> Label(root,text="Input a number:").pack()
>>> Entry(root).pack()
>>> Button(root,text="OK").pack()
```
而执行下列语句后的布局效果如图 8.16(b)所示,这里用到了 side 属性:side="left"使得构件 贴着左边放置。
```
>>> Label(root,text="Input a number:").pack(side="left")
>>> Entry(root).pack(side="left")
>>> Button(root,text="OK").pack(side="left")
```
![](https://box.kancloud.cn/2016-02-22_56cafce5b0917.png)
![](https://box.kancloud.cn/2016-02-22_56cafce5bfec2.png)
图 8.16 Pack 布局管理器
如果对窗口中的所有基本构件以打包方式布局,将使大大小小的构件形成一摞,显然不 美观。实际应用中常见的做法是对框架进行打包布局,一个一个框架像集装箱一样并排或堆 叠,然后再将基本构件作为各框架的子构件进行布局,这样能使界面整齐美观。
虽然 Pack 管理器还提供其他布局选项,但在此不多介绍了,因为我们有更灵活、更好用 的布局管理器:Grid 和 Place。
pack 方法的“逆”方法是 pack_forget 方法,意为将用 pack 布局的构件从界面中拿掉, 从而构件变成不可见。注意,这时构件作为对象仍然存在,只是未显示在界面中而已,我们 随时可以再次调用任何布局管理器方法来使构件可见。
rid 布局管理器*
Grid 布局管理器将窗口或框架视为一个由行和列构成的二维表格,并将构件放入行列交 叉处的单元格中。为了使用这种布局,只需先创建构件,再用 grid 方法的选项 row 和 column 指定行、列编号即可。不需要预先定义表格的尺寸,Grid 布局管理器会根据构件的大小自动 调整:每一列的宽度由该列中最宽的构件决定,每一行的高度由该行最高的构件决定。行、列都是从 0 开始编号,row 的缺省值为当前下一空行,column 的缺省值总为 0。可 以在布置构件时指定不连续的行号或列号,这相对于预留了一些行列,但这些预留的行列是 不可见的,因为行列上没有构件存在,也就没有宽度和高度。
Grid 布局管理器的使用非常简单,可以说是进行图形界面布局的首选工具。先看一个简 单例子:
```
>>> Label(root,text="ID Number:").grid()
>>> Label(root,text="Name:").grid()
>>> Entry(root).grid(row=0,column=1)
>>> Entry(root).grid(row=1,column=1)
```
其中第一条语句使用缺省行号 0 和缺省列号 0 来安排标签“ID Number:”,第二条语句使用缺省行号 1 和缺省列号 0 来安排标签“Name”,后面两条语句在指定的位置安排录入框。布局效果如图 8.17 所示:
![](https://box.kancloud.cn/2016-02-22_56cafce5ceada.png)
图 8.17 Grid 布局
从图 8.17 可以看出,标签构件在单元格里是居中放置的,如果觉得这种对齐方式不好看, 可以用 grid 方法的 sticky 选项来改变对齐方式。
Tkinter 中常利用“方位”概念来指定对齐方式,具体方位值包括 N、NE、E、SE、S、 SW、W、NW 和 CENTER(见图 8.18)。将 sticky 选项设置为某个方位,就表示将构件沿单元格的某条边或某个角对齐。
![](https://box.kancloud.cn/2016-02-22_56cafce5dd780.png)
图 8.18 方位
如果构件比单元格小,未能填满单元格,则可以指定如何处理多余空间,比如在水平方 向或垂直方向拉伸构件以填满单元格。可以利用方位值的组合来使构件延伸,例如若将 sticky 设置为 E+W,则构件将在水平方向延伸,占满单元格的宽度;若设置为 E+W+N+S(或 NW+SE),则构件将在水平和垂直两个方向延伸,占满整个单元格。
如果想让一个构件占据多个单元格,可以使用 grid 方法的 rowspan 和 columnspan 选项来 指定在行和列方向上的跨度。例如,下面的语句序列能产生如图 8.19 所示的复杂布局:
```
>>> Label(root,text="ID Number:").grid(sticky=E)
>>> Label(root,text="Name:").grid(sticky=E)
>>> Entry(root).grid(row=0,column=1)
>>> Entry(root).grid(row=1,column=1)
>>> Checkbutton(root,text="Registered User").grid(
... columnspan=2,sticky=W)
>>> Label(root,text="X").grid(row=0,column=2,
... columnspan=2,rowspan=2,sticky=W+E+N+S)
>>> Button(root,text="Zoom In").grid(row=2,column=2)
>>> Button(root,text="Zoom Out").grid(row=2,column=3)
```
![](https://box.kancloud.cn/2016-02-22_56cafce5eecd5.png)
图 8.19 利用 Grid 进行复杂布局
下面再看一个利用框架来实现复杂界面结构的例子:
```
>>> f1 = Frame(root,width=100,height=100,bd=4,relief="groove")
>>> f1.grid(row=1,column=1,rowspan=2,sticky=N+S+W+E)
>>> Checkbutton(f1,text="PC").grid(row=1,sticky=W)
>>> Checkbutton(f1,text="Laptop").grid(row=2,sticky=W)
>>> f2 = Frame(root,width=100,height=50,bd=4,relief="groove")
>>> f2.grid(row=1,column=2,columnspan=2,sticky=N)
>>> b1 = Button(root,text="OK",width=6)
>>> b1.grid(row=2,column=2,sticky=E+W,padx=2)
>>> b2 = Button(root,text="Cancel",width=6)
>>> b2.grid(row=2,column=3,sticky=E+W,padx=2)
```
结果如图 8.20 所示。可以看出,这个例子大致实现了图 8.2 所要求的界面。
![](https://box.kancloud.cn/2016-02-22_56cafce60d8a7.png)
图 8.20 利用框架的布局
grid 方法的“逆”方法是 grid_forget 方法,意为将用 grid 布局的构件从界面中拿掉,从 而构件变成不可见。注意,这时构件作为对象仍然存在,只是未显示在界面中而已,我们随 时可以再次调用任何布局管理器方法来使构件可见。
Place 布局管理器*
Place 布局管理器直接指定构件在父构件中的位置坐标。为使用这种布局,只需先创建构 件,再调用构件的 place 方法,该方法的选项 x 和 y 用于设定坐标。父构件(窗口或框架) 的坐标系统以左上角为(0,0),x 方向向右,y 方向向下。
由于(x,y)坐标确定的是一个点,而子构件可看作是一个矩形,这个矩形怎么放置在一个 点上呢?Place 通过“锚点”来处理这个问题:利用方位值(见图 8.18)指定子构件的锚点, 再利用 place 方法的 anchor 选项来将子构件的锚点定位于父窗口的指定坐标处。利用这种精 确的定位,可以实现一个或多个构件在窗口中的各种对齐方式。anchor 的缺省值为 NW,即 构件的左上角。例如下面两条语句分别将两个标签置于根窗口的(0,0)和(199,199)处,定位锚 点分别是(默认的)NW 和 SE:
```
>>> Label(root,text="Hello").place(x=0,y=0)
>>> Label(root,text="World").place(x=199,y=199,anchor=SE)
```
下列语句序列围绕根窗口的点(100,100)按不同锚点布置了若干个按钮:
```
>>> Button(root,text="CCCCCCCCCCCCCCCCCC").place(x=100,y=100,
... anchor=CENTER)
>>> Button(root,text=" NW ").place(x=100,y=100,anchor=NW)
>>> Button(root,text="E").place(x=100,y=100,anchor=E)
>>> Button(root,text="W").place(x=100,y=100,anchor=W)
>>> Button(root,text=" SE ").place(x=100,y=100,anchor=SE)
```
以上语句的执行结果如图 8.21 所示。
![](https://box.kancloud.cn/2016-02-22_56cafce61d913.png)
图 8.21 利用 Place 布局
Place 布局管理器既可以像上例这样用绝对坐标指定位置,也可以用相对坐标指定位置。 相对坐标通过选项 relx 和 rely 来设置,取值范围为 0~1,表示构件在父构件中的相对比例 位置,如 relx=0.5 即表示父构件 x 方向上的二分之一处。相对坐标的好处是当窗口改变大小 时,构件位置将随之调整,不像绝对坐标固定不变。例如下面这条语句将标签布置于水平方 向四分之一、垂直方向二分之一处,定位锚点是 SW:
```
Label(root,text="Hello").place(relx=0.25,rely=0.5,anchor=SW)
```
除了指定构件位置,Place 布局管理器还可以指定构件大小。既可以通过选项 width 和 heightPlace 来定义构件的绝对尺寸,也可以通过选项 relwidth 和 relheight 来定义构件的相对 尺寸(即相对于父构件两个方向上的比例值)。
Place 是最灵活的布局管理器,但用起来比较麻烦,通常不适合对普通窗口和对话框进行 布局,其主要用途是实现复合构件的定制布局。
place 方法的“逆”方法是 place_forget 方法,意为将用 place 布局的构件从界面中拿掉, 从而构件变成不可见。注意,这时构件作为对象仍然存在,只是未显示在界面中而已,我们 随时可以再次调用任何布局管理器方法来使构件可见。
- 前言
- 第 1 章 计算与计算思维
- 1.1 什么是计算?
- 1.1.1 计算机与计算
- 1.1.2 计算机语言
- 1.1.3 算法
- 1.1.4 实现
- 1.2 什么是计算思维?
- 1.2.1 计算思维的基本原则
- 1.2.2 计算思维的具体例子
- 1.2.3 日常生活中的计算思维
- 1.2.4 计算思维对其他学科的影响
- 1.3 初识 Python
- 1.3.1 Python 简介
- 1.3.2 第一个程序
- 1.3.3 程序的执行方式
- 1.3.4 Python 语言的基本成分
- 1.4 程序排错
- 1.5 练习
- 第 2 章 用数据表示现实世界
- 2.1 数据和数据类型
- 2.1.1 数据是对现实的抽象
- 2.1.1 常量与变量
- 2.1.2 数据类型
- 2.1.3 Python 的动态类型*
- 2.2 数值类型
- 2.2.1 整数类型 int
- 2.2.2 长整数类型 long
- 2.2.3 浮点数类型 float
- 2.2.4 数学库模块 math
- 2.2.5 复数类型 complex*
- 2.3 字符串类型 str
- 2.3.1 字符串类型的字面值形式
- 2.3.2 字符串类型的操作
- 2.3.3 字符的机内表示
- 2.3.4 字符串类型与其他类型的转换
- 2.3.5 字符串库 string
- 2.4 布尔类型 bool
- 2.4.1 关系运算
- 2.4.2 逻辑运算
- 2.4.3 布尔代数运算定律*
- 2.4.4 Python 中真假的表示与计算*
- 2.5 列表和元组类型
- 2.5.1 列表类型 list
- 2.5.2 元组类型 tuple
- 2.6 数据的输入和输出
- 2.6.1 数据的输入
- 2.6.2 数据的输出
- 2.6.3 格式化输出
- 2.7 编程案例:查找问题
- 2.8 练习
- 第 3 章 数据处理的流程控制
- 3.1 顺序控制结构
- 3.2 分支控制结构
- 3.2.1 单分支结构
- 3.2.2 两路分支结构
- 3.2.3 多路分支结构
- 3.3 异常处理
- 3.3.1 传统的错误检测方法
- 3.3.2 传统错误检测方法的缺点
- 3.3.3 异常处理机制
- 3.4 循环控制结构
- 3.4.1 for 循环
- 3.4.2 while 循环
- 3.4.3 循环的非正常中断
- 3.4.4 嵌套循环
- 3.5 结构化程序设计
- 3.5.1 程序开发过程
- 3.5.2 结构化程序设计的基本内容
- 3.6 编程案例:如何求 n 个数据的最大值?
- 3.6.1 几种解题策略
- 3.6.2 经验总结
- 3.7 Python 布尔表达式用作控制结构*
- 3.8 练习
- 第 4 章 模块化编程
- 4.1 模块化编程基本概念
- 4.1.1 模块化设计概述
- 4.1.2 模块化编程
- 4.1.3 编程语言对模块化编程的支持
- 4.2 Python 语言中的函数
- 4.2.1 用函数减少重复代码 首先看一个简单的用字符画一棵树的程序:
- 4.2.2 用函数改善程序结构
- 4.2.3 用函数增强程序的通用性
- 4.2.4 小结:函数的定义与调用
- 4.2.5 变量的作用域
- 4.2.6 函数的返回值
- 4.3 自顶向下设计
- 4.3.1 顶层设计
- 4.3.2 第二层设计
- 4.3.3 第三层设计
- 4.3.4 第四层设计
- 4.3.5 自底向上实现与单元测试
- 4.3.6 开发过程小结
- 4.4 Python 模块*
- 4.4.1 模块的创建和使用
- 4.4.2 Python 程序架构
- 4.4.3 标准库模块
- 4.4.4 模块的有条件执行
- 4.5 练习
- 第 5 章 图形编程
- 5.1 概述
- 5.1.1 计算可视化
- 5.1.2 图形是复杂数据
- 5.1.3 用对象表示复杂数据
- 5.2 Tkinter 图形编程
- 5.2.1 导入模块及创建根窗口
- 5.2.2 创建画布
- 5.2.3 在画布上绘图
- 5.2.4 图形的事件处理
- 5.3 编程案例
- 5.3.1 统计图表
- 5.3.2 计算机动画
- 5.4 软件的层次化设计:一个案例
- 5.4.1 层次化体系结构
- 5.4.2 案例:图形库 graphics
- 5.4.3 graphics 与面向对象
- 5.5 练习
- 第 6 章 大量数据的表示和处理
- 6.1 概述
- 6.2 有序的数据集合体
- 6.2.1 字符串
- 6.2.2 列表
- 6.2.3 元组
- 6.3 无序的数据集合体
- 6.3.1 集合
- 6.3.2 字典
- 6.4 文件
- 6.4.1 文件的基本概念
- 6.4.2 文件操作
- 6.4.3 编程案例:文本文件分析
- 6.4.4 缓冲
- 6.4.5 二进制文件与随机存取*
- 6.5 几种高级数据结构*
- 6.5.1 链表
- 6.5.2 堆栈
- 6.5.3 队列
- 6.6 练习
- 第 7 章 面向对象思想与编程
- 7.1 数据与操作:两种观点
- 7.1.1 面向过程观点
- 7.1.2 面向对象观点
- 7.1.3 类是类型概念的发展
- 7.2 面向对象编程
- 7.2.1 类的定义
- 7.2.2 对象的创建
- 7.2.3 对象方法的调用
- 7.2.4 编程实例:模拟炮弹飞行
- 7.2.5 类与模块化
- 7.2.6 对象的集合体
- 7.3 超类与子类*
- 7.3.1 继承
- 7.3.2 覆写
- 7.3.3 多态性
- 7.4 面向对象设计*
- 7.5 练习
- 第 8 章 图形用户界面
- 8.1 图形用户界面概述
- 8.1.1 程序的用户界面
- 8.1.2 图形界面的组成
- 8.1.3 事件驱动
- 8.2 GUI 编程
- 8.2.1 UI 编程概述
- 8.2.2 初识 Tkinter
- 8.2.3 常见 GUI 构件的用法
- 8.2.4 布局
- 8.2.5 对话框*
- 8.3 Tkinter 事件驱动编程
- 8.3.1 事件和事件对象
- 8.3.2 事件处理
- 8.4 模型-视图设计方法
- 8.4.1 将 GUI 应用程序封装成对象
- 8.4.2 模型与视图
- 8.4.3 编程案例:汇率换算器
- 8.5 练习
- 第 9 章 模拟与并发
- 9.1 模拟
- 9.1.1 计算机建模
- 9.1.2 随机问题的建模与模拟
- 9.1.3 编程案例:乒乓球比赛模拟
- 9.2 原型法
- 9.3 并行计算*
- 9.3.1 串行、并发与并行
- 9.3.2 进程与线程
- 9.3.3 多线程编程的应用
- 9.3.4 Python 多线程编程
- 9.3.5 小结
- 9.4 练习
- 第 10 章 算法设计和分析
- 10.1 枚举法
- 10.2 递归
- 10.3 分治法
- 10.4 贪心法
- 10.5 算法分析
- 10.5.1 算法复杂度
- 10.5.2 算法分析实例
- 10.6 不可计算的问题
- 10.7 练习
- 第 11 章 计算+X
- 11.1 计算数学
- 11.2 生物信息学
- 11.3 计算物理学
- 11.4 计算化学
- 11.5 计算经济学
- 11.6 练习
- 附录
- 1 Python 异常处理参考
- 2 Tkinter 画布方法
- 3 Tkinter 编程参考
- 3.1 构件属性值的设置
- 3.2 构件的标准属性
- 3.3 各种构件的属性
- 3.4 对话框
- 3.5 事件
- 参考文献