原文: http://zetcode.com/tkinter/layout/

在 Tkinter 教程的这一部分中,我们介绍布局管理器。

在设计应用的 GUI 时,我们决定要使用哪些小部件以及如何在应用中组织这些小部件。 为了组织小部件,我们使用专门的不可见对象,称为布局管理器。

有两种小部件:容器及其子级。 容器将子项分组为合适的布局。

Tkinter 具有三个内置的布局管理器:packgridplace管理器。 place几何管理器使用绝对定位来定位小部件。 pack几何管理器在水平和垂直框中组织窗口小部件。 grid几何管理器将小部件放置在二维网格中。

绝对定位

在大多数情况下,程序员应使用布局管理器。 在某些情况下,我们可以使用绝对定位。 在绝对定位中,程序员以像素为单位指定每个小部件的位置和大小。 如果我们调整窗口大小,则小部件的大小和位置不会改变。 在各种平台上,应用看起来都不同,在 Linux 上看起来不错,在 Mac OS 上看起来不太正常。 在我们的应用中更改字体可能会破坏布局。 如果我们将应用翻译成另一种语言,则必须重做布局。

absolute.py

  1. #!/usr/bin/env python3
  2. """
  3. ZetCode Tkinter tutorial
  4. In this script, we lay out images
  5. using absolute positioning.
  6. Author: Jan Bodnar
  7. Last modified: April 2019
  8. Website: www.zetcode.com
  9. """
  10. from PIL import Image, ImageTk
  11. from tkinter import Tk, BOTH
  12. from tkinter.ttk import Frame, Label, Style
  13. class Example(Frame):
  14. def __init__(self):
  15. super().__init__()
  16. self.initUI()
  17. def initUI(self):
  18. self.master.title("Absolute positioning")
  19. self.pack(fill=BOTH, expand=1)
  20. Style().configure("TFrame", background="#333")
  21. bard = Image.open("bardejov.jpg")
  22. bardejov = ImageTk.PhotoImage(bard)
  23. label1 = Label(self, image=bardejov)
  24. label1.image = bardejov
  25. label1.place(x=20, y=20)
  26. rot = Image.open("rotunda.jpg")
  27. rotunda = ImageTk.PhotoImage(rot)
  28. label2 = Label(self, image=rotunda)
  29. label2.image = rotunda
  30. label2.place(x=40, y=160)
  31. minc = Image.open("mincol.jpg")
  32. mincol = ImageTk.PhotoImage(minc)
  33. label3 = Label(self, image=mincol)
  34. label3.image = mincol
  35. label3.place(x=170, y=50)
  36. def main():
  37. root = Tk()
  38. root.geometry("300x280+300+300")
  39. app = Example()
  40. root.mainloop()
  41. if __name__ == '__main__':
  42. main()

在此示例中,我们使用绝对定位放置了三个图像。 我们使用位置几何图形管理器。

  1. from PIL import Image, ImageTk

我们使用 Python Imaging Library(PIL)模块中的ImageImageTk

  1. style = Style()
  2. style.configure("TFrame", background="#333")

我们使用样式将框架配置为具有深灰色背景。

  1. bard = Image.open("bardejov.jpg")
  2. bardejov = ImageTk.PhotoImage(bard)

我们从当前工作目录中的图像创建图像对象和照片图像对象。

  1. label1 = Label(self, image=bardejov)

我们用图像创建一个Label。 标签可以包含文本或图像。

  1. label1.image = bardejov

我们必须保留对图像的引用,以防止图像被垃圾收集。

  1. label1.place(x=20, y=20)

将标签放置在框架上的x = 20y = 20坐标处。

Tkinter 中的布局管理 - 图1

图:绝对定位

Tkinter 包管理器

pack几何管理器在水平和垂直框中组织窗口小部件。 布局由fillexpandside选项控制。

按钮示例

在下面的示例中,我们将两个按钮放置在窗口的右下角。 我们使用pack管理器。

buttons.py

  1. #!/usr/bin/env python3
  2. """
  3. ZetCode Tkinter tutorial
  4. In this script, we use the pack manager
  5. to position two buttons in the
  6. bottom-right corner of the window.
  7. Author: Jan Bodnar
  8. Last modified: April 2019
  9. Website: www.zetcode.com
  10. """
  11. from tkinter import Tk, RIGHT, BOTH, RAISED
  12. from tkinter.ttk import Frame, Button, Style
  13. class Example(Frame):
  14. def __init__(self):
  15. super().__init__()
  16. self.initUI()
  17. def initUI(self):
  18. self.master.title("Buttons")
  19. self.style = Style()
  20. self.style.theme_use("default")
  21. frame = Frame(self, relief=RAISED, borderwidth=1)
  22. frame.pack(fill=BOTH, expand=True)
  23. self.pack(fill=BOTH, expand=True)
  24. closeButton = Button(self, text="Close")
  25. closeButton.pack(side=RIGHT, padx=5, pady=5)
  26. okButton = Button(self, text="OK")
  27. okButton.pack(side=RIGHT)
  28. def main():
  29. root = Tk()
  30. root.geometry("300x200+300+300")
  31. app = Example()
  32. root.mainloop()
  33. if __name__ == '__main__':
  34. main()

我们有两个框架。 有一个基础框架和一个附加框架,该框架可在两个方向上扩展,并将两个按钮按到基础框架的底部。 这些按钮放置在水平框中,并位于此框的右侧。

  1. frame = Frame(self, relief=RAISED, borderwidth=1)
  2. frame.pack(fill=BOTH, expand=True)

我们创建另一个Frame小部件。 该小部件占用了大部分区域。 我们更改框架的边框,使框架可见。 默认情况下,它是平坦的。

  1. closeButton = Button(self, text="Close")
  2. closeButton.pack(side=RIGHT, padx=5, pady=5)

创建了closeButton。 将其放入水平盒中。 side参数使按钮放置在水平线的右侧。 padxpady参数在小部件之间放置了一些空间。 padx在按钮小部件之间以及closeButton和根窗口的右边框之间放置一些空间。 pady在按钮小部件与框架的边框和根窗口的边框之间放置一些空间。

  1. okButton.pack(side=RIGHT)

okButton放在closeButton旁边,它们之间有 5px 的间距。

Tkinter 中的布局管理 - 图2

图:按钮示例

回顾示例

pack管理器是一个简单的布局管理器。 它可用于执行简单的布局任务。 为了创建更复杂的布局,我们需要利用更多的框架,每个框架都有自己的包管理器。

review.py

  1. #!/usr/bin/env python3
  2. """
  3. ZetCode Tkinter tutorial
  4. In this example, we use the pack
  5. manager to create a review example.
  6. Author: Jan Bodnar
  7. Last modified: April 2019
  8. Website: www.zetcode.com
  9. """
  10. from tkinter import Tk, Text, TOP, BOTH, X, N, LEFT
  11. from tkinter.ttk import Frame, Label, Entry
  12. class Example(Frame):
  13. def __init__(self):
  14. super().__init__()
  15. self.initUI()
  16. def initUI(self):
  17. self.master.title("Review")
  18. self.pack(fill=BOTH, expand=True)
  19. frame1 = Frame(self)
  20. frame1.pack(fill=X)
  21. lbl1 = Label(frame1, text="Title", width=6)
  22. lbl1.pack(side=LEFT, padx=5, pady=5)
  23. entry1 = Entry(frame1)
  24. entry1.pack(fill=X, padx=5, expand=True)
  25. frame2 = Frame(self)
  26. frame2.pack(fill=X)
  27. lbl2 = Label(frame2, text="Author", width=6)
  28. lbl2.pack(side=LEFT, padx=5, pady=5)
  29. entry2 = Entry(frame2)
  30. entry2.pack(fill=X, padx=5, expand=True)
  31. frame3 = Frame(self)
  32. frame3.pack(fill=BOTH, expand=True)
  33. lbl3 = Label(frame3, text="Review", width=6)
  34. lbl3.pack(side=LEFT, anchor=N, padx=5, pady=5)
  35. txt = Text(frame3)
  36. txt.pack(fill=BOTH, pady=5, padx=5, expand=True)
  37. def main():
  38. root = Tk()
  39. root.geometry("300x300+300+300")
  40. app = Example()
  41. root.mainloop()
  42. if __name__ == '__main__':
  43. main()

该示例显示了如何创建具有多个框架和包装管理器的更复杂的布局。

  1. self.pack(fill=BOTH, expand=True)

第一个框架是基础框架,其他框架放置在该基础框架上。 请注意,除了在框架内组织子代外,我们还在基础框架上管理框架。

  1. frame1 = Frame(self)
  2. frame1.pack(fill=X)
  3. lbl1 = Label(frame1, text="Title", width=6)
  4. lbl1.pack(side=LEFT, padx=5, pady=5)
  5. entry1 = Entry(frame1)
  6. entry1.pack(fill=X, padx=5, expand=True)

前两个小部件放置在第一帧上。 使用fillexpand参数水平拉伸该条目。

  1. frame3 = Frame(self)
  2. frame3.pack(fill=BOTH, expand=True)
  3. lbl3 = Label(frame3, text="Review", width=6)
  4. lbl3.pack(side=LEFT, anchor=N, padx=5, pady=5)
  5. txt = Text(frame3)
  6. txt.pack(fill=BOTH, pady=5, padx=5, expand=True)

在第三帧内,我们放置一个标签和一个文本小部件。 标签固定在北方。 文本小部件将占据整个剩余区域。

Tkinter 中的布局管理 - 图3

图:回顾 example

Tkinter 网格管理器

Tkinter 的grid几何管理器用于创建计算器的骨架。

calculator.py

  1. #!/usr/bin/env python3
  2. """
  3. ZetCode Tkinter tutorial
  4. In this script, we use the grid manager
  5. to create a skeleton of a calculator.
  6. Author: Jan Bodnar
  7. Last modified: April 2019
  8. Website: www.zetcode.com
  9. """
  10. from tkinter import Tk, W, E
  11. from tkinter.ttk import Frame, Button, Entry, Style
  12. class Example(Frame):
  13. def __init__(self):
  14. super().__init__()
  15. self.initUI()
  16. def initUI(self):
  17. self.master.title("Calculator")
  18. Style().configure("TButton", padding=(0, 5, 0, 5),
  19. font='serif 10')
  20. self.columnconfigure(0, pad=3)
  21. self.columnconfigure(1, pad=3)
  22. self.columnconfigure(2, pad=3)
  23. self.columnconfigure(3, pad=3)
  24. self.rowconfigure(0, pad=3)
  25. self.rowconfigure(1, pad=3)
  26. self.rowconfigure(2, pad=3)
  27. self.rowconfigure(3, pad=3)
  28. self.rowconfigure(4, pad=3)
  29. entry = Entry(self)
  30. entry.grid(row=0, columnspan=4, sticky=W+E)
  31. cls = Button(self, text="Cls")
  32. cls.grid(row=1, column=0)
  33. bck = Button(self, text="Back")
  34. bck.grid(row=1, column=1)
  35. lbl = Button(self)
  36. lbl.grid(row=1, column=2)
  37. clo = Button(self, text="Close")
  38. clo.grid(row=1, column=3)
  39. sev = Button(self, text="7")
  40. sev.grid(row=2, column=0)
  41. eig = Button(self, text="8")
  42. eig.grid(row=2, column=1)
  43. nin = Button(self, text="9")
  44. nin.grid(row=2, column=2)
  45. div = Button(self, text="/")
  46. div.grid(row=2, column=3)
  47. fou = Button(self, text="4")
  48. fou.grid(row=3, column=0)
  49. fiv = Button(self, text="5")
  50. fiv.grid(row=3, column=1)
  51. six = Button(self, text="6")
  52. six.grid(row=3, column=2)
  53. mul = Button(self, text="*")
  54. mul.grid(row=3, column=3)
  55. one = Button(self, text="1")
  56. one.grid(row=4, column=0)
  57. two = Button(self, text="2")
  58. two.grid(row=4, column=1)
  59. thr = Button(self, text="3")
  60. thr.grid(row=4, column=2)
  61. mns = Button(self, text="-")
  62. mns.grid(row=4, column=3)
  63. zer = Button(self, text="0")
  64. zer.grid(row=5, column=0)
  65. dot = Button(self, text=".")
  66. dot.grid(row=5, column=1)
  67. equ = Button(self, text="=")
  68. equ.grid(row=5, column=2)
  69. pls = Button(self, text="+")
  70. pls.grid(row=5, column=3)
  71. self.pack()
  72. def main():
  73. root = Tk()
  74. app = Example()
  75. root.mainloop()
  76. if __name__ == '__main__':
  77. main()

网格管理器用于组织框架容器中的按钮。

  1. Style().configure("TButton", padding=(0, 5, 0, 5),
  2. font='serif 10')

我们将Button小部件配置为具有特定的字体并具有一些内部填充。

  1. self.columnconfigure(0, pad=3)
  2. ...
  3. self.rowconfigure(0, pad=3)

我们使用columnconfigure()rowconfigure()方法在网格列和行中定义一些空间。 这样,我们可以实现按钮之间有一定的间隔。

  1. entry = Entry(self)
  2. entry.grid(row=0, columnspan=4, sticky=W+E)

Entry小部件是显示数字的地方。 小部件放置在第一行中,它横跨所有四列。 小部件可能不会占用网格中单元所分配的所有空间。 sticky参数沿给定方向扩展小部件。 在我们的案例中,我们确保条目小部件从左向右展开。

  1. cls = Button(self, text="Cls")
  2. cls.grid(row=1, column=0)

cls按钮位于第二行和第一列。 请注意,行和列从零开始。

  1. self.pack()

pack()方法显示框架小部件并为其指定初始大小。 如果没有给出其他参数,则大小将足以显示所有子项。 此方法将框架窗口小部件打包到顶级根窗口,该窗口也是一个容器。 grid几何管理器用于组织框架小部件中的按钮。

Tkinter 中的布局管理 - 图4

图:计算器

Windows 示例

以下示例使用grid几何管理器创建 Windows 对话框。

windows.py

  1. #!/usr/bin/env python3
  2. """
  3. ZetCode Tkinter tutorial
  4. In this script, we use the grid
  5. manager to create a more complicated Windows
  6. layout.
  7. Author: Jan Bodnar
  8. Last modified: April 2019
  9. Website: www.zetcode.com
  10. """
  11. from tkinter import Tk, Text, BOTH, W, N, E, S
  12. from tkinter.ttk import Frame, Button, Label, Style
  13. class Example(Frame):
  14. def __init__(self):
  15. super().__init__()
  16. self.initUI()
  17. def initUI(self):
  18. self.master.title("Windows")
  19. self.pack(fill=BOTH, expand=True)
  20. self.columnconfigure(1, weight=1)
  21. self.columnconfigure(3, pad=7)
  22. self.rowconfigure(3, weight=1)
  23. self.rowconfigure(5, pad=7)
  24. lbl = Label(self, text="Windows")
  25. lbl.grid(sticky=W, pady=4, padx=5)
  26. area = Text(self)
  27. area.grid(row=1, column=0, columnspan=2, rowspan=4,
  28. padx=5, sticky=E+W+S+N)
  29. abtn = Button(self, text="Activate")
  30. abtn.grid(row=1, column=3)
  31. cbtn = Button(self, text="Close")
  32. cbtn.grid(row=2, column=3, pady=4)
  33. hbtn = Button(self, text="Help")
  34. hbtn.grid(row=5, column=0, padx=5)
  35. obtn = Button(self, text="OK")
  36. obtn.grid(row=5, column=3)
  37. def main():
  38. root = Tk()
  39. root.geometry("350x300+300+300")
  40. app = Example()
  41. root.mainloop()
  42. if __name__ == '__main__':
  43. main()

在此示例中,我们使用Label小部件,Text小部件和四个按钮。

  1. self.columnconfigure(1, weight=1)
  2. self.columnconfigure(3, pad=7)
  3. self.rowconfigure(3, weight=1)
  4. self.rowconfigure(5, pad=7)

我们在网格中的小部件之间定义一些空间。 weight参数使第二列和第四行可增长。 该行和列被文本小部件占据,因此所有多余的空间都被它占用。

  1. lbl = Label(self, text="Windows")
  2. lbl.grid(sticky=W, pady=4, padx=5)

标签窗口小部件已创建并放入网格中。 如果未指定列和行,则假定为第一列或行。 该标签向西粘贴,其边框周围有一些填充物。

  1. area = Text(self)
  2. area.grid(row=1, column=0, columnspan=2, rowspan=4,
  3. padx=5, sticky=E+W+S+N)

文本窗口小部件已创建,并从第二行和第一列开始。 它跨越两列和四行。 小部件和根窗口的左边框之间有 4px 的间距。 最终,小部件将粘在所有四个方面。 因此,调整窗口大小时,文本小部件会向各个方向扩展。

  1. abtn = Button(self, text="Activate")
  2. abtn.grid(row=1, column=3)
  3. cbtn = Button(self, text="Close")
  4. cbtn.grid(row=2, column=3, pady=4)

这两个按钮位于文本小部件旁边。

  1. hbtn = Button(self, text="Help")
  2. hbtn.grid(row=5, column=0, padx=5)
  3. obtn = Button(self, text="OK")
  4. obtn.grid(row=5, column=3)

这两个按钮位于文本小部件下方; “帮助”按钮占据第一列,“确定”按钮占据最后一列。

Tkinter 中的布局管理 - 图5

图:窗口示例

在 Tkinter 教程的这一部分中,我们介绍了小部件的布局管理。