3、窗口控件配置管理员
在设计GUI程序时,可以使用三种方法包装和定位各组件在容器或窗口内的位置,这三个方法又称窗口控件配置管理员。
(1) pack方法
虽然我们称pack方法,其实在tkinter内这是一个类别。这是最常使用的控件配置管理方法,它是使用相对位置的概念处理widget控件配置,至于控件的正确位置则是由pack方法自动完成。pack方法的语法格式如下:
pack(option, ...)
option参数可以是side、fill、padx/pady、ipadx/ipady、anchor。
side参数
side参数可以垂直或水平配置控件,再进一步讲解前先看下列程序实例
from tkinter import *
window = Tk()
window.title("ch3_1")
lab1 = Label(window, text="明志科技大学", bg="lightyellow")
lab2 = Label(window, text="长庚大学", bg="lightgreen")
lab3 = Label(window, text="长庚科技大学", bg="lightblue")
lab1.pack()
lab2.pack()
lab3.pack()
window.mainloop()
由运行上面代码可以看到,当窗口中有多个组件时,使用pack可以让组件由上往下排列显示,这也是系统的默认设置。使用pack方法时,也可以增加side参数设置组件的排列方式,此参数的取值如下:
TOP:这是默认值,由上往下排列
BOTTOM:由下往上排列。
LEFT:由左往右排列
RIGHT:由右往左排列
from tkinter import *
Reliefs = ["flat", "groove", "raised", "ridge", "solid", "sunken"]
root = Tk()
root.title("ch3_5")
for relief in Reliefs:
Label(root, text=relief, relief=relief, fg="blue", font=("Time", 20, "bold")).pack(side=LEFT, padx=5)
root.mainloop()
运行结果

from tkinter import *
bitMaps = ["error", "hourglass", "info", "questhead", "question", "warning", "gray12", "gray25", "gray50", "gray75"]
root = Tk()
root.title("ch3_5")
for bitmap in bitMaps:
Label(root, bitmap=bitmap).pack(side=LEFT, padx=5)
root.mainloop()

padx/pady参数
在使用pack方法时,可以使用padx/pady参数设定控件边界与容器(可想成窗口边界)的距离或是控件边界的距离。在默认环境下窗口控件间的距离是1像素,如果希望有适度间距,可以设置参数padx/pady,代表水平间距/垂直间距,可以分别在组件间增加间距。
from tkinter import *
window = Tk()
window.title("ch3_1")
lab1 = Label(window, text="明志科技大学", bg="lightyellow", width=15)
lab2 = Label(window, text="长庚大学", bg="lightgreen", width=15)
lab3 = Label(window, text="长庚科技大学", bg="lightblue", width=15)
lab1.pack(side=LEFT)
lab2.pack(side=LEFT, padx=10)
lab3.pack(side=LEFT)
window.mainloop()
ipadx/ipdy参数
ipadx参数可以控制标签文字与标签容器的x轴间距,ipady参数可以控制标签文字与标签容器的y轴间距。
from tkinter import *
window = Tk()
window.title("ch3_1")
lab1 = Label(window, text="明志科技大学", bg="lightyellow", width=15)
lab2 = Label(window, text="长庚大学", bg="lightgreen", width=15)
lab3 = Label(window, text="长庚科技大学", bg="lightblue", width=15)
lab1.pack()
lab2.pack(ipadx=10)
lab3.pack(ipady=10)
window.mainloop()
执行结果

anchor参数
anchor参数可以设定widget控件在窗口中的位置,与属性设置中的类似,但是本节中是指控件内容在控件区域的位置设置(实际的例子中是指标签文字在标签区域的位置)
| NW | N | NE | ||
| W | CNETER | E | ||
| SW | S | SE |
from tkinter import *
window = Tk()
window.title("ch3_12")
window.geometry("300x180")
okLabel = Label(window, text="OK", font="Times 20 bold", fg="white", bg="blue")
okLabel.pack(anchor=S, side=RIGHT, padx=10, pady=10)
noLabel = Label(window, text="NO", font="Times 20 bold", fg="white", bg="red")
noLabel.pack(anchor=S, side=RIGHT, pady=10)
window.mainloop()
运行结果

fill参数
fill参数的主要功能是告诉pack管理程序,设置控件填满所分配容器区间的方式,如果是fill=X表示控件可以填满所分配空间的X轴不留白,如果是fill=Y表示控件可以填满所分配控件的Y轴不留白,如果是fill=BOTH表示控件可以填满所分配空间的X轴和Y轴。fill默认值是NONE,表示保持原大小。
from tkinter import *
window = Tk()
window.title("ch3_14")
lab1 = Label(window, text="明志科技大学", bg="lightyellow", width=15)
lab2 = Label(window, text="长庚大学", bg="lightgreen", width=15)
lab3 = Label(window, text="长庚科技大学", bg="lightblue", width=15)
lab1.pack(side=LEFT, fill=Y)
lab2.pack(fill=X)
lab3.pack(fill=BOTH)
window.mainloop()
运行结果

从上诉结果来看,fill=BOTH并没有发挥作用,在扩充窗口大小时并没有扩充给Y轴的空间。原因是当Widget空间从左到右配置时,pack配置管理员所配置的空间是Y轴的空间。当Widget控件从上到下配置时,pack配置管理员所配置的空间是X轴的空间。以上诉实例而言,当扩展窗口大小时,“长庚科技大学”标签在Y轴的空间称为额外空间,这时需要借助expand参数设置。
expand参数
expand参数可设定Widget控件是否填满额外的父容器控件,默认是False(或是0),表示不填满,如果是True(或是1)表示填满。
from tkinter import *
window = Tk()
window.title("ch3_21")
Label(window, text="Mississippi", bg="red", fg="white", font="Times 20 bold").pack(fill=X)
Label(window, text="Kentucky", bg="green", fg="white", font="Arial 20 bold italic").pack(fill=BOTH, expand=True)
Label(window, text="Purdue", bg="blue", fg="white", font="Times 24 bold").pack(fill=X)
window.mainloop()
pack的方法
pack其实在python tkinter中是一个类别,它提供下列方法供我们使用。
| 方法名称 | 说明 |
| slaves() | 传回所有Widget控件对象 |
| info() | 传回pack选项的对应值 |
| forget() | 隐藏Widget控件,可以用pack(option,...)复原显示 |
| location(x, y) | 传回此点是否在单元格,如果是传回坐标,如果不是传回(-1,-1) |
| size() | 传回Widget控件大小 |
| propagate(boolean) | 参数是True表示父窗口大小由子控件决定,默认是True |
from tkinter import *
window = Tk()
window.title("ch3_23")
window.geometry("300x180")
print("执行前", window.pack_slaves())
okLabel = Label(window, text="OK", bg="blue", fg="white", font="Times 20 bold")
okLabel.pack(anchor=S, side=RIGHT, padx=10, pady=10)
noLabel = Label(window, text="NO", bg="red", fg="white", font=("Times", 20, "bold"))
noLabel.pack(anchor=S, side=RIGHT, pady=10)
print("执行后", window.pack_slaves())
window.mainloop()
(2) grid方法
这是一种以格状或者类似Excel电子表格方式包装和定位窗口组件的方法。grid方法的格式如下:
grid(option, ...)
options参数可以是row、column、padx/pady,rowspan、columnspan、sticky,下面将详细说明。
row和column
row和column的取值row=0 ... row = n, column=0 ... column=n
可以适度调整grid()方法内的row和column值,即可包装窗口组件的位置。
from tkinter import *
window = Tk()
window.title("ch3_24")
lab1 = Label(window, text="明志科技大学", bg="lightyellow", width=15)
lab2 = Label(window, text="长庚大学", bg="lightgreen", width=15)
lab3 = Label(window, text="长庚科技大学", bg="lightblue", width=15)
lab1.grid(row=0, column=0)
lab2.grid(row=1, column=0)
lab3.grid(row=1, column=1)
window.mainloop()
运行结果

columnspan参数
可以设定控件在column方向的合并数量,在正式讲解columnspan参数功能前,下面先介绍建立一个含8个标签的应用。
from tkinter import *
window = Tk()
window.title("ch3_26")
lab1 = Label(window, text="标签1", relief="raised")
lab2 = Label(window, text="标签2", relief="raised")
lab3 = Label(window, text="标签3", relief="raised")
lab4 = Label(window, text="标签4", relief="raised")
lab5 = Label(window, text="标签5", relief="raised")
lab6 = Label(window, text="标签6", relief="raised")
lab7 = Label(window, text="标签7", relief="raised")
lab8 = Label(window, text="标签8", relief="raised")
lab1.grid(row=0, column=0)
lab2.grid(row=0, column=1)
lab3.grid(row=0, column=2)
lab4.grid(row=0, column=3)
lab5.grid(row=1, column=0)
lab6.grid(row=1, column=1)
lab7.grid(row=1, column=2)
lab8.grid(row=1, column=3)
window.mainloop()
执行结果

如果发生了标签2和标签3的区间被一个标签占用的情况,此时就是使用columnspan参数的场合。
from tkinter import *
window = Tk()
window.title("ch3_26")
lab1 = Label(window, text="标签1", relief="raised")
lab2 = Label(window, text="标签2", relief="raised")
lab4 = Label(window, text="标签4", relief="raised")
lab5 = Label(window, text="标签5", relief="raised")
lab6 = Label(window, text="标签6", relief="raised")
lab7 = Label(window, text="标签7", relief="raised")
lab8 = Label(window, text="标签8", relief="raised")
lab1.grid(row=0, column=0)
lab2.grid(row=0, column=1, columnspan=2)
lab4.grid(row=0, column=3)
lab5.grid(row=1, column=0)
lab6.grid(row=1, column=1)
lab7.grid(row=1, column=2)
lab8.grid(row=1, column=3)
window.mainloop()
运行结果

rowspan参数
可以设定控件在row方向的合并数。
from tkinter import *
window = Tk()
window.title("ch3_26")
lab1 = Label(window, text="标签1", relief="raised")
lab2 = Label(window, text="标签2", relief="raised")
lab3 = Label(window, text="标签3", relief="raised")
lab4 = Label(window, text="标签4", relief="raised")
lab5 = Label(window, text="标签5", relief="raised")
lab7 = Label(window, text="标签7", relief="raised")
lab8 = Label(window, text="标签8", relief="raised")
lab1.grid(row=0, column=0)
lab2.grid(row=0, column=1, rowspan=2)
lab3.grid(row=0, column=2)
lab4.grid(row=0, column=3)
lab5.grid(row=1, column=0)
lab7.grid(row=1, column=2)
lab8.grid(row=1, column=3)
window.mainloop()
运行结果

如果标签2,标签3,标签6,标签7同时合并成一个标签,那么columnspan和rowspan参数都要设置。
padx和pady参数
这两个参数的用法与上一小节pack方法的padx/pady参数相同。
from tkinter import *
window = Tk()
window.title("ch3_26")
lab1 = Label(window, text="标签1", relief="raised")
lab2 = Label(window, text="标签2", relief="raised")
lab3 = Label(window, text="标签3", relief="raised")
lab4 = Label(window, text="标签4", relief="raised")
lab5 = Label(window, text="标签5", relief="raised")
lab6 = Label(window, text="标签6", relief="raised")
lab7 = Label(window, text="标签7", relief="raised")
lab8 = Label(window, text="标签8", relief="raised")
lab1.grid(row=0, column=0, padx=5, pady=5)
lab2.grid(row=0, column=1, padx=5, pady=5)
lab3.grid(row=0, column=2, padx=5, pady=5)
lab4.grid(row=0, column=3, padx=5, pady=5)
lab5.grid(row=1, column=0, padx=5)
lab6.grid(row=1, column=1, padx=5)
lab7.grid(row=1, column=2, padx=5)
lab8.grid(row=1, column=3, padx=5)
window.mainloop()
运行结果

sticky参数
这个参数的功能类似anchor,但是只可以设定N/S/W/E,即上/下/左/右对齐。原则上相同的column的Widget控件,如果宽度不同时,grid方法会保留最宽的控件当作基准,这时比较短的控件会居中对齐,参考以下实例。
from tkinter import *
window = Tk()
window.title("ch3_31")
lab1 = Label(window, text="明志工专")
lab2 = Label(window, bg="yellow", width=20)
lab3 = Label(window, text="明志科技大学")
lab4 = Label(window, bg="aqua", width=20)
lab1.grid(row=0, column=0, padx=5, pady=5)
lab2.grid(row=0, column=1, padx=5, pady=5)
lab3.grid(row=1, column=0, padx=5)
lab4.grid(row=1, column=1, padx=5)
window.mainloop()
运行结果

从上图可以看到“明志工专”标签时居中对齐。
from tkinter import *
window = Tk()
window.title("ch3_31")
lab1 = Label(window, text="明志工专")
lab2 = Label(window, bg="yellow", width=20)
lab3 = Label(window, text="明志科技大学")
lab4 = Label(window, bg="aqua", width=20)
lab1.grid(row=0, column=0, padx=5, pady=5, sticky=W)
lab2.grid(row=0, column=1, padx=5, pady=5)
lab3.grid(row=1, column=0, padx=5)
lab4.grid(row=1, column=1, padx=5)
window.mainloop()
运行结果

sticky参数的可能值N/S/W/E也可以组合使用。
sticky=N+S:可以拉长高度让控件在顶端和底端对齐。
sticky=W+E:可以拉长宽度让控件在左边和右边对齐。
sticky=N+S+E:可以拉长高度让控件在顶端和底端对齐,同时切齐右边。
sticky=N+S+W:可以拉长高度让控件在顶端和底端对齐,同时切齐左边。
sticky=N+S+W+E:可以拉长高度让控件在顶端和底端对齐,同时切齐左右边。
观察下面代码
from tkinter import *
window = Tk()
window.title("ch3_31")
lab1 = Label(window, text="明志工专", relief="raised")
lab2 = Label(window, bg="yellow", width=20)
lab3 = Label(window, text="明志科技大学", relief="raised")
lab4 = Label(window, bg="aqua", width=20)
lab1.grid(row=0, column=0, padx=5, pady=5)
lab2.grid(row=0, column=1, padx=5, pady=5)
lab3.grid(row=1, column=0, padx=5)
lab4.grid(row=1, column=1, padx=5)
window.mainloop()
运行结果

上述程序的目的主要时了解标签的宽度。
下面这个程序主要时观察“明志工专”标签被拉长后的结果。
from tkinter import *
window = Tk()
window.title("ch3_31")
lab1 = Label(window, text="明志工专", relief="raised")
lab2 = Label(window, bg="yellow", width=20)
lab3 = Label(window, text="明志科技大学", relief="raised")
lab4 = Label(window, bg="aqua", width=20)
lab1.grid(row=0, column=0, padx=5, pady=5, sticky=W+E)
lab2.grid(row=0, column=1, padx=5, pady=5)
lab3.grid(row=1, column=0, padx=5)
lab4.grid(row=1, column=1, padx=5)
window.mainloop()
运行结果

grid方法的应用
from tkinter import *
window = Tk()
window.title("ch3_35")
Colors = ["red", "orange", "yellow", "green", "blue", "purple"]
r = 0
for color in Colors:
Label(window, text=color, relief="groove", width=20).grid(row=r, column=0)
Label(window, bg=color, relief="ridge", width=20).grid(row=r, column=1)
r += 1
window.mainloop()
运行结果

rowconfigure()和columnconfigure()
在设计Widget控件的布局时,有时候会碰上窗口缩放大小,此时可以使用这个两个方法设计底几个row或column的缩放比例。例如
rowconfigure(0, weight=1) # row 0的控件当窗口改变大小时缩放比是1
columnconfigure(0, weight=1) # column 0的控件当窗口改变大小时缩放比是1
下面程序认识rowconfigure()和columnconfigure()与sticky参数的用法,此处不使用sticky参数。
from tkinter import *
window = Tk()
window.title("ch3_35")
window.rowconfigure(1, weight=1)
window.columnconfigure(0, weight=1)
lab1 = Label(window, text="Label 1", bg="pink")
lab1.grid(row=0, column=0, padx=5, pady=5)
lab2 = Label(window, text="Label 2", bg="lightblue")
lab2.grid(row=0, column=1, padx=5, pady=5)
lab3 = Label(window, bg="yellow")
lab3.grid(row=1, column=0, columnspan=2, padx=5, pady=5)
window.mainloop()
运行结果

上面代码中特别使用底色表达各个标签所占据的空间,可以看到在没有使用sticky参数的情况下,各个控件所占据的空间。
from tkinter import *
window = Tk()
window.title("ch3_35")
window.rowconfigure(1, weight=1)
window.columnconfigure(0, weight=1)
lab1 = Label(window, text="Label 1", bg="pink")
lab1.grid(row=0, column=0, padx=5, pady=5, sticky=W)
lab2 = Label(window, text="Label 2", bg="lightblue")
lab2.grid(row=0, column=1, padx=5, pady=5)
lab3 = Label(window, bg="yellow")
lab3.grid(row=1, column=0, columnspan=2, padx=5, pady=5, sticky=N+S+W+E)
window.mainloop()
运行结果

通过上诉执行结果可以得知下方的标签控件可以随着窗口大小更改,主要是上面的代码中“sticky=N+S+W+E”的结果。至于设置的“sticky=W”,会让lab1控件向左对齐。
(3) place方法
这是使用直接指定方式将Widget控件放在容器(可想成窗口)中的方法。这个方法的语法格式如下。
place(option, ...)
option参数可以是height/width、relx/rely、x/y、relheight/relwidth、bordermode、anchor,下面将详细介绍。
x/y参数
place()方法内的x和y参数可直接设定窗口组件的左上方位置,单位是像素。窗口显示区的左上角是(x=0, y=0),x是向右递增,y是向下递增。同时使用这种方法时,窗口将不会自动重设大小而是使用默认的大小显示,参考下面代码。
from tkinter import *
window = Tk()
window.title("ch3_36")
lab1 = Label(window, text="明志科技大学", bg="lightyellow", width=15)
lab2 = Label(window, text="长庚大学", bg="lightgreen", width=15)
lab3 = Label(window, text="长庚科技大学", bg="lightblue", width=15)
lab1.place(x=0, y=0)
lab2.place(x=30, y=50)
lab3.place(x=60,y=100)
window.mainloop()
运行结果

width/height参数
有时候在设计窗口应用程序时,所预留的控件有限,如果想要将图片插入窗口内,却担心图片太大,可以在插入图片时同时设定图片的大小,此时可以使用width/height参数,这两个参数可以直接设定Widget控件的实体大小。
在窗口内直接设置图片控件的位置和大小。
from tkinter import *
window = Tk()
window.title("ch3_37")
window.geometry("640x480")
night = PhotoImage(file="test.png")
labl = Label(window, image=night)
labl.place(x=20, y=30, width=200, height=120)
snow = PhotoImage(file="test.png")
lab2 = Label(window, image=snow)
lab2.place(x=200, y=200, width=400, height=240)
window.mainloop()
运行结果

relx/rely参数与relwidth/relheight参数
relx/rely可以设置相对于父容器(可想成父窗口)的位置,relwidth/relheight设置相对大小,这个相对位置与相对大小是相对于父窗口而言,其值为0.0 ~ 1.0。
下面程序将图片test.png从相对位置(0.1, 0.1)开始放置,相对大小是(0.8, 0.8)。
from tkinter import *
window = Tk()
window.title("ch3_38")
window.geometry("640x480")
night = PhotoImage(file="test.png")
labl = Label(window, image=night)
labl.place(relx=0.1, rely=0.1, relwidth=0.8, relheight=0.8)
window.mainloop()
运行结果

在设计时,如果参数的某个相对大小未设定(可能是relwidth或relheight),未设置的部分将以实际大小显示,此时可能需要放大窗口宽度才可以显示。
Widget控件位置总结
我们使用tkinter模块设计GUI程序时,虽然可以使用place()方法很精确地设置控件的位置,不过建议尽量使用pack()和grid()方法定位组件,因为当窗口中组件较多时,使用place()计算组件位置较不方便,同时如有新增或减少组件时又须重新计算设置组件位置,这样会不方便。
转载自 CSDN-专业IT技术社区
原文链接:https://blog.csdn.net/weixin_71243777/article/details/162706653



