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的尺寸均会跟着同步。

推荐阅读更多精彩内容