Python Tkinter 窗口的管理与设置(四):布局管理器
Python爬虫、数据分析、网站开发等案例教程视频免费在线观看
https://space.bilibili.com/523606542
前言
什么是布局管理器?说白了就是管理你的那些组件如何排列的家伙。Tkinter有三个布局管理器,分别是pack、grid和place,其中:
pack是按添加顺序排列组件。
grid是按行/列形式排列组件。
place允许程序员指定组件的大小和位置。
pack
pack其实之前的例子一直在用,对比grid管理器,pack更适用于少量组件的排列,但它在使用上更加简单。如果需要创建相对复杂的布局结构,那么建议是使用多个框架(Frame)结构,或者使用grid管理器实现。
不要在同一个父组件中混合使用pack和grid,因为Tkinter会很认真地在那儿计算到底先使用哪个布局管理器……以至于你等了半个小时,Tkinter还在那儿纠结不出结果!
我们常常会遇到的一个情况是将一个组件放到一个容器组件中,并填充整个父组件。下面生成一个Listbox组件并将它填充到root窗口中:
import tkinter as tk root = tk.Tk() listbox = tk.Listbox(root) listbox.pack(fill=tk.BOTH, expand=True) for i in range(10): listbox.insert(tk.END, str(i)) root.mainloop()
其中,fill选项是告诉窗口管理器该组件将填充整个分配给它的空间,BOTH表示同时横向和纵向扩展,X表示横向,Y表示纵向;expand选项是告诉窗口管理器将父组件的额外空间也填满。
默认情况下,pack是将添加的组件依次纵向排列:
import tkinter as tk root = tk.Tk() tk.Label(root,text="Red",bg="red",fg="white").pack(fill=tk.X) tk.Label(root,text="Green",bg="green",fg="black").pack(fill=tk.X) tk.Label(root,text="Blue",bg="blue",fg="white").pack(fill=tk.X) tk.mainloop()
如果想要组件横向挨个儿排列,可以使用side选项:
import tkinter as tk root = tk.Tk() tk.Label(root,text="Red",bg="red",fg="white").pack(side=tk.LEFT) tk.Label(root,text="Green",bg="green",fg="black").pack(side=tk.LEFT) tk.Label(root,text="Blue",bg="blue",fg="white").pack(side=tk.LEFT) tk.mainloop()
grid
grid管理器可以说是Tkinter这三个布局管理器中最灵活多变的。当你在设计对话框的时候,使用gird尤其便捷。如果你此前一直在用pack构造窗口布局,那么学习完grid你会悔恨当初为啥不早学它。使用一个grid就可以简单地实现你用很多个框架和pack搭建起来的效果。
使用grid排列组件,只需告诉它你想要将组件放置的位置(行/列,row选项指定行,cloumn选项指定列)。此外,你并不用提前指出网格(grid分布给组件的位置称为网格)的尺寸,因为管理器会自动计算
import tkinter as tk root = tk.Tk() # column默认值是0 tk.Entry(root).grid(row=0, column=0) tk.Entry(root).grid(row=0, column=1) tk.Entry(root).grid(row=0, column=3) tk.Entry(root).grid(row=1, column=0) # tk.Entry(root).grid(row=1, column=1) tk.Entry(root).grid(row=1, column=3) tk.mainloop()
登录表单
import tkinter as tk root = tk.Tk() root.geometry("300x300+150+150") # column默认值是0 tk.Label(root, text="用户名").grid(row=0, column=0, sticky=tk.W) tk.Entry(root) .grid(row=0, column=1) tk.Label(root, text="密码") .grid(row=1, column=0, sticky=tk.W) tk.Entry(root, show="*") .grid(row=1, column=1) tk.mainloop()
默认情况下组件会居中显示在对应的网格里,你可以使用sticky选项来修改这一特性。该选项可以使用的值有E、W、S、N(EWSN分别表示东西南北,即上北下南左西右东)以及它们的组合。因此,可以通过sticky=W使得Label左对齐:
tk.Label(root, text="密码") .grid(row=1, column=0, sticky=tk.W) tk.Entry(root, show="*") .grid(row=1, column=1)
有时候可能需要用几个网格来放置一个组件,可以做到吗?当然可以,只需要指定rowspan和columnspan就可以实现跨行和跨列的功能:
跨行和跨列布局
import tkinter as tk root = tk.Tk() # column默认值是0 tk.Label(root, text="用户名").grid(row=0,column=0,sticky=tk.W) tk.Entry(root) .grid(row=0, column=1) tk.Label(root, text="密码") .grid(row=1, column=0, sticky=tk.W) tk.Entry(root, show="*") .grid(row=1, column=1) photo = tk.PhotoImage(file="../../../assets/logo.png") tk.Label(root,image=photo).grid(row=0,column=2,rowspan=2, padx=5, pady=5) tk.Button(text="提交",width=10).grid(row=2,column=0,columnspan=3, pady=5) tk.mainloop()
place
通常情况下不建议使用place布局管理器,因为对比起pack和grid,place要做更多的工作。不过纯在即合理,place在一些特殊的情况下可以发挥妙用。请看下面的例子。
使用place,可以将子组件显示在父组件的正中间:
import tkinter as tk root = tk.Tk() def callback(): print("正中靶心") tk.Button(root, text="点我",command=callback).place(relx=0.5, rely=0.5, anchor=tk.CENTER) tk.mainloop
在某种情况下,或许你希望一个组件可以覆盖另一个组件,那么place又可以派上用场了。下面例子演示用Button覆盖Label组件:
import tkinter as tk root = tk.Tk() def callback(): print("正中靶心") photo = tk.PhotoImage(file="../../assets/logo.png") tk.Label(root, image=photo).pack() tk.Button(root, text="点我",command=callback).place(relx=0.5, rely=0.5, anchor=tk.CENTER) tk.mainloop()
利用 place 覆盖组件
不难看出,relx和rely选项指定的是相对于父组件的位置,范围是00~1.0,因此0.5表示位于正中间。那么relwidth和relheight选项则是指定相对于父组件的尺寸:
相对位置和相对尺寸
import tkinter as tk root = tk.Tk() tk.Label(root, bg="red").place(relx=0.5, rely=0.5, relheight=0.75, relwidth=0.75, anchor=tk.CENTER) tk.Label(root, bg="yellow").place(relx=0.5, rely=0.5, relheight=0.5, relwidth=0.5, anchor=tk.CENTER) tk.Label(root, bg="green").place(relx=0.5, rely=0.5, relheight=0.25, relwidth=0.25, anchor=tk.CENTER) tk.mainloop()
对于上面的代码,无论你如何拉伸改变窗口,三个 Label的尺寸均会跟着同步。