【问题标题】:How to configure row/column sizes in grid managed frames in a python tkinter class project如何在 python tkinter 类项目中的网格管理框架中配置行/列大小
【发布时间】:2019-06-09 21:34:14
【问题描述】:

我正在使用 Tkinter 和类在 python 中创建一个 GUI,并且在调整网格打包器中特定行的大小时遇到​​了问题。

我附加的代码有效,但我想控制行宽,以便前 2 个框架的大小是静态的,而底部的大小随窗口调整。我在参考不同的解决方案时尝试了很多东西,但没有任何效果。

# !/usr/bin/python3

# Use Tkinter for python 2, tkinter for python 3
import tkinter as tk

# Main Window
class WinMain(tk.Frame):
    def __init__(self, master):
        # parameters that you want to send through the Frame class. 
        tk.Frame.__init__(self, master)

        # reference to the master widget, which is the tk window
        self.master = master

        # with that, we want to then run init_window, which doesn't yet exist
        self.init_window()

    def init_window(self):
        # changing the title of our master widget      
        self.master.title("GUI Tester")

        # Create menu for window
        self.createMenu()

        # Create Gui for window
        self.createGui()

        # Update Gui every second after 1 second
        self.after(1000, self.upDateGui)

    def createMenu(self):
        # Initialise drop-down menu
        menu = tk.Menu(self.master)
        self.master.config(menu=menu)

        # Add drop-down menu for Options
        options = tk.Menu(menu, tearoff=False)
        menu.add_cascade(label="Options", menu=options)
        options.add_command(label="Open...", command=self.menuOptionsOpen)
        options.add_separator()
        options.add_command(label="Close", command=self.menuOptionsClose)

        # Add drop-down menu for Help
        help = tk.Menu(menu, tearoff=False)
        menu.add_cascade(label="Help", menu=help)
        help.add_command(label="About...", command=self.menuHelpAbout)

    def createGui(self):
        # Define GUI using Grid to place widgets
        # Size window to its minimum set to 2/3 of the screen resolution
        top = self.winfo_toplevel()

        screen_width = top.winfo_screenwidth()
        screen_height = top.winfo_screenheight()
        screen_resolution = str(int(screen_width * 2 / 3)) + 'x' + str(int(screen_height * 2 / 3))

        top.geometry(screen_resolution)
        top.minsize(int(screen_width * 1 / 3), int(screen_height * 1 / 3))

        # ------------------------------------------------
        # create all frames
        # ------------------------------------------------
        self.c = self.master
        self.c.frameTop = tk.LabelFrame(self.c, text="Top", width=5, height=5, padx=5, pady=5)
        self.c.frameMiddle = tk.LabelFrame(self.c, text="Middle", width=5, height=5, padx=5, pady=5)
        self.c.frameBottom = tk.LabelFrame(self.c, text="Bottom", width=5, height=5, padx=5, pady=5)
        self.c.frameRight = tk.Frame(self.c, borderwidth=5, relief=tk.GROOVE)

        # ------------------------------------------------
        # Create widgets for frameTop
        # ------------------------------------------------
        # Text Box
        self.c.frameTop.textBox = tk.Text(self.c.frameTop, borderwidth=3, relief=tk.SUNKEN)
        self.c.frameTop.textBox.config(font=("consolas", 12), undo=True, wrap='none')

        # Text Box Scroll Bars
        self.c.frameTop.textBoxYScroll = tk.Scrollbar(self.c.frameTop, orient=tk.VERTICAL,
                                                      command=self.c.frameTop.textBox.yview)
        self.c.frameTop.textBox['yscrollcommand'] = self.c.frameTop.textBoxYScroll.set

        self.c.frameTop.textBoxXScroll = tk.Scrollbar(self.c.frameTop, orient=tk.HORIZONTAL,
                                                      command=self.c.frameTop.textBox.xview)
        self.c.frameTop.textBox['xscrollcommand'] = self.c.frameTop.textBoxXScroll.set
        # ------------------------------------------------
        # Create widgets for frameMiddle
        # ------------------------------------------------
        # Text Box
        self.c.frameMiddle.textBox = tk.Text(self.c.frameMiddle, borderwidth=3, relief=tk.SUNKEN)
        self.c.frameMiddle.textBox.config(font=("consolas", 12), undo=True, wrap='none')

        # Text Box Scroll Bars
        self.c.frameMiddle.textBoxYScroll = tk.Scrollbar(self.c.frameMiddle, orient=tk.VERTICAL,
                                                         command=self.c.frameMiddle.textBox.yview)
        self.c.frameMiddle.textBox['yscrollcommand'] = self.c.frameMiddle.textBoxYScroll.set

        self.c.frameMiddle.textBoxXScroll = tk.Scrollbar(self.c.frameMiddle, orient=tk.HORIZONTAL,
                                                         command=self.c.frameMiddle.textBox.xview)
        self.c.frameMiddle.textBox['xscrollcommand'] = self.c.frameMiddle.textBoxXScroll.set
        # ------------------------------------------------
        # Create widgets for frameBottom
        # ------------------------------------------------
        # Text Box
        self.c.frameBottom.textBox = tk.Text(self.c.frameBottom, borderwidth=3, relief=tk.SUNKEN)
        self.c.frameBottom.textBox.config(font=("consolas", 12), undo=True, wrap='none')

        # Text Box Scroll Bars
        self.c.frameBottom.textBoxYScroll = tk.Scrollbar(self.c.frameBottom, orient=tk.VERTICAL,
                                                         command=self.c.frameBottom.textBox.yview)
        self.c.frameBottom.textBox['yscrollcommand'] = self.c.frameBottom.textBoxYScroll.set

        self.c.frameBottom.textBoxXScroll = tk.Scrollbar(self.c.frameBottom, orient=tk.HORIZONTAL,
                                                         command=self.c.frameBottom.textBox.xview)
        self.c.frameBottom.textBox['xscrollcommand'] = self.c.frameBottom.textBoxXScroll.set
        # ------------------------------------------------
        # Create widgets for frameRight
        # ------------------------------------------------
        self.c.frameRight.btnStatus = tk.Button(self.c.frameRight, text='Status Window', command=self.launchWinStatus)
        self.c.frameRight.btnSpare1 = tk.Button(self.c.frameRight, text='Send Middle', command=self.btnSpare1)
        self.c.frameRight.btnSpare2 = tk.Button(self.c.frameRight, text='Spare 2', command=self.btnSpare2)

        # ------------------------------------------------

        # ------------------------------------------------
        # Layout widgets in frameTop
        # ------------------------------------------------
        self.c.frameTop.grid_columnconfigure(0, weight=1)
        self.c.frameTop.grid_columnconfigure(1, weight=0)
        self.c.frameTop.grid_rowconfigure(0, weight=1)
        self.c.frameTop.grid_rowconfigure(1, weight=0)

        self.c.frameTop.textBox.grid(row=0, column=0, sticky="nsew")
        self.c.frameTop.textBoxYScroll.grid(row=0, column=1, sticky="nsew")
        self.c.frameTop.textBoxXScroll.grid(row=1, column=0, sticky="nsew")
        # ------------------------------------------------
        # Layout widgets in frameMiddle
        # ------------------------------------------------
        self.c.frameMiddle.grid_columnconfigure(0, weight=1)
        self.c.frameMiddle.grid_columnconfigure(1, weight=0)
        self.c.frameMiddle.grid_rowconfigure(0, weight=1)
        self.c.frameMiddle.grid_rowconfigure(1, weight=0)

        self.c.frameMiddle.textBox.grid(row=0, column=0, sticky="nsew")
        self.c.frameMiddle.textBoxYScroll.grid(row=0, column=1, sticky="nsew")
        self.c.frameMiddle.textBoxXScroll.grid(row=1, column=0, sticky="nsew")
        # ------------------------------------------------
        # Layout widgets in frameBottom
        # ------------------------------------------------
        self.c.frameBottom.grid_columnconfigure(0, weight=1)
        self.c.frameBottom.grid_columnconfigure(1, weight=0)
        self.c.frameBottom.grid_rowconfigure(0, weight=1)
        self.c.frameBottom.grid_rowconfigure(1, weight=0)

        self.c.frameBottom.textBox.grid(row=0, column=0, sticky="nsew")
        self.c.frameBottom.textBoxYScroll.grid(row=0, column=1, sticky="nsew")
        self.c.frameBottom.textBoxXScroll.grid(row=1, column=0, sticky="nsew")
        # ------------------------------------------------
        # Layout widgets in frameRight
        # ------------------------------------------------
        self.c.frameRight.grid_columnconfigure(0, weight=0)
        self.c.frameRight.grid_rowconfigure(0, weight=0)

        self.c.frameRight.btnStatus.grid(row=0, column=0, sticky="nsew")
        self.c.frameRight.btnSpare1.grid(row=2, column=0, sticky="nsew")
        self.c.frameRight.btnSpare2.grid(row=3, column=0, sticky="nsew")
        # ------------------------------------------------
        # Layout frames in top container
        # ------------------------------------------------
        numOfCols = 2
        numOfRows = 6

        self.c.grid_columnconfigure(0, weight=1, pad=3)
        self.c.grid_columnconfigure(1, weight=0, pad=3)

        self.c.grid_rowconfigure(0, weight=1, pad=3)
        self.c.grid_rowconfigure(1, weight=1, pad=3)
        self.c.grid_rowconfigure(2, weight=1, pad=3)
        self.c.grid_rowconfigure(3, weight=1, pad=3)
        self.c.grid_rowconfigure(4, weight=1, pad=3)
        self.c.grid_rowconfigure(5, weight=1, pad=3)

        frameTopRowCol = [0, 0]
        frameTopSpan = [2, 1]

        frameMiddleRowCol = [frameTopRowCol[0] + frameTopSpan[0],
                             frameTopRowCol[1]]
        frameMiddleSpanRC = [2, 1]

        frameBottomRowCol = [frameMiddleRowCol[0] + frameMiddleSpanRC[0],
                             frameMiddleRowCol[1]]
        frameBottomSpanRC = [2, 1]

        frameRightRowCol = [frameTopRowCol[0],
                            frameTopRowCol[1] + frameTopSpan[1]]
        frameRightSpanRC = [numOfRows, 1]

        self.c.frameTop.grid(row=frameTopRowCol[0], column=frameTopRowCol[1],
                             rowspan=frameTopSpan[0], columnspan=frameTopSpan[1], sticky="nsew")
        self.c.frameMiddle.grid(row=frameMiddleRowCol[0], column=frameMiddleRowCol[1],
                                rowspan=frameMiddleSpanRC[0], columnspan=frameMiddleSpanRC[1], sticky="nsew")
        self.c.frameBottom.grid(row=frameBottomRowCol[0], column=frameBottomRowCol[1],
                                rowspan=frameBottomSpanRC[0], columnspan=frameBottomSpanRC[1], sticky="nsew")
        self.c.frameRight.grid(row=frameRightRowCol[0], column=frameRightRowCol[1],
                               rowspan=frameRightSpanRC[0], columnspan=frameRightSpanRC[1], sticky="nsew")

        # ------------------------------------------------
        # Layout top container in window
        # ------------------------------------------------
        self.grid_columnconfigure(0, weight=1, pad=3)
        self.grid_rowconfigure(1, weight=1, pad=3)

        # ------------------------------------------------
        # Layout window
        # ------------------------------------------------
        top.grid_columnconfigure(0, weight=1, pad=3)
        top.grid_rowconfigure(1, weight=1, pad=3)

    def menuOptionsOpen(self):
        print("menuOptionsOpen")

    def menuOptionsClose(self):
        print("menuOptionsClose")

    def menuHelpAbout(self):
        print("menuHelpAbout")

    def launchWinStatus(self):
        print ("launchWinStatus")

    def btnSpare1(self):
        print("btnSpare1")

    def btnSpare2(self):
        print("btnSpare2")

    def upDateGui(self):
        print("upDateGui")

        # Perform update every x milliseconds
        self.after(1000, self.upDateGui)

# Main
def main():
    root = tk.Tk()
    app = WinMain(root)
    root.mainloop()

# Launch Main
if __name__ == '__main__':
    main()

我在第 174 行有一个部分,我可以在其中更改行配置权重,这具有我无法解释的特殊效果。它应该能够固定某些行的高度,同时允许其他行随着窗口缩小到最小尺寸而增长/缩小。

【问题讨论】:

    标签: python class tkinter grid


    【解决方案1】:

    有几点:

    有很多代码与问题无关。

    您构建了一个令人困惑的小部件层次结构。 WinMain() 类 以 root 作为 master 实例化。而WinMain() 继承Frame(), 你从来没有把任何小部件放在 self.然后创建名称top = self.winfo_toplevel(),即正在运行的Tk() 实例=root=master=self.master=self.c

    您对符号的使用令人困惑;

    self.c.frameTop.textBox = tk.Text(self.c.frameTop, ...
    

    为什么要在 frameTop 的 textBox 属性中保存对 Text 小部件的引用?

    最后您在self 中配置网格(不包含任何内容的框架) 和root

    我认为你的大部分问题是因为你混淆了事物的名称。我在下面提供了一个示例,其中仅包含获得正确行为所需的代码。我使用 bg 颜色是为了便于识别不同的小部件。

    import tkinter as tk
    
    # Main Window
    class WinMain(tk.Frame):
        def __init__(self, master):
            tk.Frame.__init__(self, master)
            self.master = master
            self.master.config(bg='tan')
            master.geometry('600x400+800+50')
            self.pack(padx=10, pady=10, expand=True, fill='both')
            self.columnconfigure(0, weight=1)
            self.rowconfigure(2, weight=1)     # Expand cols 0 & 2 with resize
    
            # Top
            frameTop = tk.LabelFrame(self, text="Top", bg='peru')
            frameTop.grid(row=0, column=0, sticky='nsew')
            frameTop.columnconfigure(0, weight=1)   # Expand frame with resize
            frameTop.rowconfigure(0, weight=1)
            Top_Box = tk.Text(frameTop, borderwidth=3, relief=tk.SUNKEN, width=20, height=2)
            Top_Box.grid(row=0, column=0, sticky="nsew", padx=10, pady=10)
    
            # Middle
            frameMiddle = tk.LabelFrame(self, text="Middle", padx=5, pady=5, bg='tomato')
            frameMiddle.grid(row=1, column=0, sticky='nsew')
            frameMiddle.columnconfigure(0, weight=1)   # Expand frame with resize
            frameMiddle.rowconfigure(0, weight=1)
            Middle_Box = tk.Text(frameMiddle, borderwidth=3, relief=tk.SUNKEN, width=20, height=2)
            Middle_Box.grid(row=0, column=0, sticky="nsew", padx=10, pady=10)
    
            # Bottom
            frameBottom = tk.LabelFrame(self, text="Bottom", padx=5, pady=5, bg='khaki')
            frameBottom.grid(row=2, column=0, sticky='nsew')
            frameBottom.columnconfigure(0, weight=1)   # Expand frame with resize
            frameBottom.rowconfigure(0, weight=1)
            Bottom_Box = tk.Text(frameBottom, borderwidth=3, relief=tk.SUNKEN, width=20, height=2)
            Bottom_Box.grid(row=0, column=0, sticky="nsew", padx=10, pady=10)
    
            # Right
            frameRight = tk.Frame(self, borderwidth=5, relief=tk.GROOVE, bg='thistle')
            frameRight.grid(row=0, column=1, rowspan=3, sticky='nsew')
            btnStatus = tk.Button(frameRight, text='Status Window',)
            btnSpare1 = tk.Button(frameRight, text='Send Middle')
            btnSpare2 = tk.Button(frameRight, text='Spare 2')
            btnStatus.grid(row=0, column=0, sticky="ew")
            btnSpare1.grid(row=1, column=0, sticky="ew")
            btnSpare2.grid(row=2, column=0, sticky="ew")
    
    if __name__ == '__main__':
        root = tk.Tk()
        app = WinMain(root)
        root.mainloop()
    

    【讨论】:

    • 感谢您这么快回复我。我目前无法尝试您的解决方案,但是当我这样做时,我会告诉您我是怎么做到的
    • 感谢您的回答。在您的帮助下,我设法让我的 GUI 按预期执行。我需要自我。对我的小部件的引用,以便其他类函数可以访问它们。起初我忽略了文本框的宽度和高度,GUI 仍然没有按我喜欢的方式缩放,但是在添加了这些参数之后它工作得很好。再次感谢。 @figbeam
    猜你喜欢
    • 1970-01-01
    • 2021-01-22
    • 1970-01-01
    • 2018-04-05
    • 2022-10-24
    • 1970-01-01
    • 2021-05-20
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多