tkinter:框架和网格

tkinter: Frame and grid

我这辈子都无法理解如何使用 grid() 来管理 Frame(Python 3.6 中的小部件).下面的代码尝试在根 window.

中显示 ListBoxes 的 2×2 矩阵
    import tkinter as TK

    root = TK.Tk()
    root.title('My App')
    rootWidth = 768
    rootHeight = 768
    root.geometry('{}x{}+0+0'.format(rootWidth, rootHeight))
    root.resizable(width=False, height=False)

    frame00 = TK.Frame(root, bd=2, relief=TK.SUNKEN)
    box00 = TK.Listbox(frame00, bd=0)
    box10 = TK.Listbox(frame00, bd=0)

    box00.grid(row=0, sticky=TK.N)
    box10.grid(row=1, sticky=TK.S)
    frame00.grid(row=0, column=0, sticky=TK.W)
    frame00.rowconfigure(0, weight=1)
    frame00.rowconfigure(1, weight=1)


    frame01 = TK.Frame(root, bd=2, relief=TK.SUNKEN)
    box01 = TK.Listbox(frame01, bd=0)
    box11 = TK.Listbox(frame01, bd=0)

    box01.grid(row=0, sticky=TK.N)
    box11.grid(row=1, sticky=TK.S)
    frame01.grid(row=0, column=1, sticky=TK.E)
    frame01.rowconfigure(0, weight=1)
    frame01.rowconfigure(1, weight=2)

    root.grid_rowconfigure(0, weight=1)
    root.grid_columnconfigure(0, weight=1)
    root.grid_columnconfigure(1, weight=1)

    for i in range(20):
        box00.insert(TK.END, 'test')
        box10.insert(TK.END, 'test')
        box01.insert(TK.END, 'test')
        box11.insert(TK.END, 'test')

最后,我在我的 GUI 中只看到两个 ListBoxes(即只有一行)而不是 4 个。 但是,如果我对每个 ListBox 使用一个 Frame,那么一切正常。

    import tkinter as TK

    root = TK.Tk()
    root.title('My App')
    rootWidth = 768
    rootHeight = 768
    root.geometry('{}x{}+0+0'.format(rootWidth, rootHeight))
    root.resizable(width=False, height=False)

    frame00 = TK.Frame(root, bd=2, relief=TK.SUNKEN)
    box00 = TK.Listbox(frame00, bd=0)
    frame10 = TK.Frame(root, bd=2, relief=TK.RAISED)
    box10 = TK.Listbox(frame10, bd=0)

    box00.grid(row=0, sticky=TK.N)
    box10.grid(row=0, sticky=TK.S)
    frame00.grid(row=0, column=0, sticky=TK.W)
    frame10.grid(row=1, column=0, sticky=TK.W)


    frame01 = TK.Frame(root, bd=2, relief=TK.SUNKEN)
    box01 = TK.Listbox(frame01, bd=0)
    frame11 = TK.Frame(root, bd=2, relief=TK.RAISED)
    box11 = TK.Listbox(frame11, bd=0)

    box01.grid(row=0, sticky=TK.N)
    box11.grid(row=0, sticky=TK.S)
    frame01.grid(row=0, column=1, sticky=TK.E)
    frame11.grid(row=1, column=1, sticky=TK.E)

    root.grid_rowconfigure(0, weight=1)
    root.grid_columnconfigure(0, weight=1)
    root.grid_columnconfigure(1, weight=1)

    for i in range(20):
        box00.insert(TK.END, 'test')
        box10.insert(TK.END, 'test')
        box01.insert(TK.END, 'test')
        box11.insert(TK.END, 'test')

是不是Frame里面只能用pack()

更新

线程中的人指出,在原始代码列表中,我没有在那些 grid() 调用中使用 column 关键字参数。事实上,我做到了,只是我在发布前的最近一次尝试中删除了它们,结果基本上是一样的。

这是一个包含 column 参数的新版本,它也只显示两个 ListBoxes。

root = TK.Tk()
root.title('Script Launcher')
rootWidth = 768
rootHeight = 768
root.geometry('{}x{}+0+0'.format(rootWidth, rootHeight))
root.resizable(width=False, height=False)

frame00 = TK.Frame(root, bd=2, relief=TK.SUNKEN)
box00 = TK.Listbox(frame00, bd=0)
box10 = TK.Listbox(frame00, bd=0)

box00.grid(row=0, column=0, sticky=TK.N)
box10.grid(row=1, column=0, sticky=TK.S)
frame00.grid(row=0, column=0, sticky=TK.W)
frame00.rowconfigure(0, weight=1)
frame00.rowconfigure(1, weight=1)
frame00.columnconfigure(0, weight=1)


frame01 = TK.Frame(root, bd=2, relief=TK.SUNKEN)
box01 = TK.Listbox(frame01, bd=0)
box11 = TK.Listbox(frame01, bd=0)

box01.grid(row=0, column=1,  sticky=TK.N)
box11.grid(row=1, column=1, sticky=TK.S)
frame01.grid(row=0, column=1, sticky=TK.E)
frame01.rowconfigure(0, weight=1)
frame01.rowconfigure(1, weight=1)
frame01.columnconfigure(0, weight=1)

root.grid_rowconfigure(0, weight=1)
root.grid_columnconfigure(0, weight=1)
root.grid_columnconfigure(1, weight=1)

for name in range(20)
    box00.insert(TK.END, 'test')
    box10.insert(TK.END, 'test')
    box01.insert(TK.END, 'test')
    box11.insert(TK.END, 'test')


root.mainloop()

您忘记将 column 添加到 grid 请参阅此示例。

box00.grid(row=0, column=45, sticky=TK.N)

grid 的工作方式类似于 excel sheet 与 rowscolumn

检查此 link 以阅读更多相关信息。那里有很好的记录。

完整代码

import tkinter as TK

root = TK.Tk()
root.title('My App')
rootWidth = 768
rootHeight = 768
root.geometry('{}x{}+0+0'.format(rootWidth, rootHeight))
root.resizable(width=False, height=False)

frame00 = TK.Frame(root, bd=2, relief=TK.SUNKEN)
box00 = TK.Listbox(frame00, bd=0)
box10 = TK.Listbox(frame00, bd=0)

box00.grid(row=0, column=75, sticky=TK.N)
box10.grid(row=1, column=5, sticky=TK.S)
frame00.grid(row=0, column=0, sticky=TK.W)
frame00.rowconfigure(0, weight=1)
frame00.rowconfigure(1, weight=1)

frame01 = TK.Frame(root, bd=2, relief=TK.SUNKEN)
box01 = TK.Listbox(frame01, bd=0)
box11 = TK.Listbox(frame01, bd=0)

box01.grid(row=0, column=7, sticky=TK.N)
box11.grid(row=1, column=60,  sticky=TK.S)
frame01.grid(row=0, column=1, sticky=TK.E)
frame01.rowconfigure(0, weight=1)
frame01.rowconfigure(1, weight=2)

root.grid_rowconfigure(0, weight=1)
root.grid_columnconfigure(0, weight=1)
root.grid_columnconfigure(1, weight=1)

for i in range(20):
    box00.insert(TK.END, 'test')
    box10.insert(TK.END, 'test')
    box01.insert(TK.END, 'test')
    box11.insert(TK.END, 'test')

root.mainloop()

您可以在 Frame 中使用 grid()。这是一个例子。希望对你有帮助...

    import tkinter as tk
    from tkinter import *
    from tkinter import ttk

    class GUI:

        def __init__(self, master):
            mainframe = ttk.Frame(master)
            mainframe.grid(column=0, row=0, sticky=(N, W, E, S))
            mainframe.columnconfigure(0, weight=1)
            mainframe.rowconfigure(0, weight=1)
            list1 = Listbox(master, bd=0)
            list1.grid(column=0, row=0)
            list2 = Listbox(master, bd=0)
            list2.grid(column=1, row=0)
            separator1 = Frame(list1, height=2, bd=1, relief=SUNKEN)
            separator1.grid(column=0, row=0)
            separator2 = Frame(list1, height=2, bd=1, relief=SUNKEN)
            separator2.grid(column=1, row=0)
            separator3 = Frame(list2, height=2, bd=1, relief=SUNKEN)
            separator3.grid(column=2, row=0)
            separator4 = Frame(list2, height=2, bd=1, relief=SUNKEN)
            separator4.grid(column=3, row=0)
            e1 = Label(separator1, text='Label1')
            e1.grid(sticky=W+E)
            e2= Label(separator2, text='Label2')
            e2.grid(sticky=W+E)
            e3 = Label(separator3, text='Label3')
            e3.grid(sticky=W+E)
            e4= Label(separator4, text='Label4')
            e4.grid(sticky=W+E)    

    root = Tk()
    my_gui = GUI(root)
    root.mainloop()

这里有一个很好的 tkinter 解释 http://effbot.org/tkinterbook/grid.htm

grid() 方法告诉 GridManager 如何处理调用 grid() 的小部件。因此,如果您调用 Tk().grid(),那将毫无意义。我更喜欢使用像 MyApp 这样的 class 作为所有内部小部件的基本级别 "wrapper"。

在我的系统上重写,生成如下形式的 GUI:

-----------------------------------
|                |                |
|                |                |
|    ListBox     |     ListBox    |
|                |                |
|                |                |
-----------------------------------
|                |                |
|                |                |
|    ListBox     |     ListBox    |
|                |                |
|                |                |
-----------------------------------

外层是TK.Tk(),它的第一个内层是TK.Frame()。然后就是分成左右两个,各一个TK.Frame()。看起来像:

-----------------------------------
|                |                |
|                |                |
|                |                |
|                |                |
|                |                |
|     Frame      |      Frame     |
|                |                |
|                |                |
|                |                |
|                |                |
|                |                |
-----------------------------------

然后我们通过设置行的权重将每个内部框架垂直网格化。

import tkinter as TK

class MyApp(TK.Frame):

    def __init__(self, master):
        super().__init__(master) # initialize the 'TK.Frame'

        # configure the root Frame (i.e. 'self')
        self.master = master # just for reference later
        self.master.grid_rowconfigure(0, weight = 1)
        self.master.grid_columnconfigure(0, weight = 1)
        self.grid(column = 0, row = 0, sticky = 'nsew')
        self.grid_rowconfigure(0, weight = 1)
        self.grid_columnconfigure(0, weight = 1) # columns will split space
        self.grid_columnconfigure(1, weight = 1) # columns will split space

        # configure internal left Frame
        self.left_frame = TK.Frame(self, borderwidth = 2, relief = TK.SUNKEN)
        self.left_frame.grid_rowconfigure(0, weight = 1) # rows will split space
        self.left_frame.grid_rowconfigure(1, weight = 1) # rows will split space
        self.left_frame.grid_columnconfigure(0, weight = 1)
        self.left_frame.grid(column = 0, row = 0, sticky = 'nsew')
        self.left_box0 = TK.Listbox(self.left_frame, borderwidth = 0)
        self.left_box0.grid(column = 0, row = 0, sticky = 'nsew')
        self.left_box1 = TK.Listbox(self.left_frame, borderwidth = 0)
        self.left_box1.grid(column = 0, row = 1, sticky = 'nsew')

        # configure internal right Frame
        self.right_frame = TK.Frame(self, borderwidth = 2, relief = TK.SUNKEN)
        self.right_frame.grid_rowconfigure(0, weight = 1) # rows will split space
        self.right_frame.grid_rowconfigure(1, weight = 1) # rows will split space
        self.right_frame.grid_columnconfigure(0, weight = 1)
        self.right_frame.grid(column = 1, row = 0, sticky = 'nsew')
        self.right_box0 = TK.Listbox(self.right_frame, borderwidth = 0)
        self.right_box0.grid(column = 0, row = 0, sticky = 'nsew')
        self.right_box1 = TK.Listbox(self.right_frame, borderwidth = 0)
        self.right_box1.grid(column = 0, row = 1, sticky = 'nsew')

        for i in range(20):
            self.left_box0.insert(TK.END, 'test')
            self.left_box1.insert(TK.END, 'test')
            self.right_box0.insert(TK.END, 'test')
            self.right_box1.insert(TK.END, 'test')


if __name__ == '__main__': # get in the habit of doing this
    root = TK.Tk()
    root.title('My App')
    root.geometry('{}x{}'.format(768, 768))
    root.resizable(width = False, height = False)
    app = MyApp(root)
    app.mainloop()