如何用pack或grid实现以下Tkinter GUI布局?

3 投票
1 回答
6903 浏览
提问于 2025-04-16 10:32

这是我目前为我的跳棋游戏设计的界面布局:

跳棋游戏

从图中可以看到,界面上方有一个菜单,左边是一个画布,我在上面绘制棋盘,右上角有一个工具栏(框架),里面放了各种格式化和导航按钮,还有一个文本框,用来记录棋子的移动。目前,我使用的是网格布局来安排这些组件。

我需要做的事情有:

  1. 当文本内容超过文本框的大小时,能够显示或隐藏滚动条。(根据这篇文章,这似乎需要使用网格布局。)
  2. 通过一个设置对话框来改变文本框中的字体和/或大小,并且不留奇怪的空隙在文本框周围。(这似乎需要使用包布局,因为文本框的宽度和高度只能用字符来设置,而不是像素……这意味着当我改变字体或大小时,文本框会变大或变小,而使用网格布局时,窗口不会自动调整。我尝试使用Font.measure来根据选择的字体调整文本框的大小,但仍然会出现空隙,因为我无法将文本框调整到精确的像素大小。)
  3. 我的最终解决方案需要能够在多个平台上使用(包括Windows和Linux,最好还有Mac)。

我可以使用哪种布局来满足我的需求?如果没有一种布局能完全满足,那哪种布局(网格或包)能让我离目标更近一些?谢谢!

1 个回答

6

对于这个简单的布局,你可以使用 gridpack 或者两者结合。对于这个情况,它们没有明显的优劣之分。两者都能实现你想要的自适应大小的效果。

我个人的想法是,先用一个横向的框架来放按钮,然后把按钮放进去。接着,我可能会用 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()

撰写回答