如何用pack或grid实现以下Tkinter GUI布局?
这是我目前为我的跳棋游戏设计的界面布局:
从图中可以看到,界面上方有一个菜单,左边是一个画布,我在上面绘制棋盘,右上角有一个工具栏(框架),里面放了各种格式化和导航按钮,还有一个文本框,用来记录棋子的移动。目前,我使用的是网格布局来安排这些组件。
我需要做的事情有:
- 当文本内容超过文本框的大小时,能够显示或隐藏滚动条。(根据这篇文章,这似乎需要使用网格布局。)
- 通过一个设置对话框来改变文本框中的字体和/或大小,并且不留奇怪的空隙在文本框周围。(这似乎需要使用包布局,因为文本框的宽度和高度只能用字符来设置,而不是像素……这意味着当我改变字体或大小时,文本框会变大或变小,而使用网格布局时,窗口不会自动调整。我尝试使用Font.measure来根据选择的字体调整文本框的大小,但仍然会出现空隙,因为我无法将文本框调整到精确的像素大小。)
- 我的最终解决方案需要能够在多个平台上使用(包括Windows和Linux,最好还有Mac)。
我可以使用哪种布局来满足我的需求?如果没有一种布局能完全满足,那哪种布局(网格或包)能让我离目标更近一些?谢谢!
1 个回答
6
对于这个简单的布局,你可以使用 grid
、pack
或者两者结合。对于这个情况,它们没有明显的优劣之分。两者都能实现你想要的自适应大小的效果。
我个人的想法是,先用一个横向的框架来放按钮,然后把按钮放进去。接着,我可能会用 grid
来把工具栏、文本框和滚动条放在另一个框架里。其实用 pack
也可以,两者都能实现。这就解决了右侧的布局。
如果你想要像图片里那样的菜单栏(也就是不太标准,只在棋盘上方),我会用类似的方法:再创建一个框架,左边放菜单栏在上面,棋盘在下面。
然后我会在主窗口里使用 pack
,把状态栏放在底部,棋盘放在左边,文本区域放在右边。
不过,使用标准的菜单栏会更好,这样就不需要为棋盘和菜单栏组合再创建一个框架了。
这里有一个简单的解决方案,使用标准的菜单栏。这种方法是把大部分控件放在父容器里,然后用 in_
参数把它们放到一个容器中。这样以后更改布局会更简单,因为你只需要调整控件在容器里的位置,而不需要调整整个层级结构。
import Tkinter as tk
import random
class App(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
size = 40
menubar = tk.Menu(self)
menubar.add_cascade(label="Game")
menubar.add_cascade(label="Options")
menubar.add_cascade(label="Help")
chessboard = tk.Canvas(width=8*size, height=8*size, borderwidth = 0,
highlightthickness=0)
statusbar = tk.Label(self, borderwidth=1, relief="sunken")
right_panel = tk.Frame(self, borderwidth = 1, relief="sunken")
scrollbar = tk.Scrollbar(orient="vertical", borderwidth=1)
# N.B. height is irrelevant; it will be as high as it needs to be
text = tk.Text(background="white",width=40, height=1, borderwidth=0, yscrollcommand=scrollbar.set)
scrollbar.config(command=text.yview)
toolbar = tk.Frame(self)
for i in range(10):
b = tk.Button(self, text="B%s" % i, borderwidth=1)
b.pack(in_=toolbar, side="left")
self.config(menu=menubar)
statusbar.pack(side="bottom", fill="x")
chessboard.pack(side="left", fill="both", expand=False)
toolbar.grid(in_=right_panel, row=0, column=0, sticky="ew")
right_panel.pack(side="right", fill="both", expand=True)
text.grid(in_=right_panel, row=1, column=0, sticky="nsew")
scrollbar.grid(in_=right_panel, row=1, column=1, sticky="ns")
right_panel.grid_rowconfigure(1, weight=1)
right_panel.grid_columnconfigure(0, weight=1)
if __name__ == "__main__":
app = App()
app.mainloop()