【问题标题】:Getting nested frame to fill remaining window space inside parent cell that already fills获取嵌套框架以填充已填充的父单元格内的剩余窗口空间
【发布时间】:2019-09-03 17:35:27
【问题描述】:

谁能帮我让我的嵌套框架在其父单元格内填充剩余的窗口空间? 我创建了应用程序窗口,给了它一个容器,根据有多少页面给了容器 2 行和动态列。我的容器是父容器。 通过将权重 1 赋予第二行并使第一列扩展到所有可用列,我已经能够用父单元格填充窗口。然后我将嵌套框架(这是页面)插入第二行,在第一行中每个页面的按钮下方。但是,即使我删除了所有网格使用,我似乎也遇到了包和网格层次结构的问题。就像 tk.Tk() 在调用时由网格自动控制。

第 41 行似乎是我可以在页面上进行打包填充和展开的地方。但它会导致层次结构错误,即使在删除所有网格使用并用包替换必要的网格之后。通过使用网格,没有这条线它运行良好。只是无法填充/扩展

import tkinter as tk
from tkinter import font as tkfont


class Application(tk.Tk):

    def __init__(self, title, page_list):
        tk.Tk.__init__(self)

        self.minsize(500, 500)
        self.maxsize(500, 500)
        self.update_idletasks()
        self.title_font = tkfont.Font(family="Helvetica", size=10, weight="bold", slant="italic")

        self.title(title)

#    Create the main container. Row 1 holds page buttons. Row 2 is for the page frame.
        container = tk.Frame(self)
        container.configure(bg="red")
        container.pack(side="top", fill="both", expand=True)
        container.grid_rowconfigure(1, weight=1)
        container.grid_columnconfigure(len(page_list), weight=1)

#    Begin making the pages and put them in a dictionary to grab by name.
        self.pages = {}
        self.p_names = page_list
        for P in self.p_names:
            page_name = P.__name__
            page = P(parent=container, controller=self, title=page_name.strip("Page"))
            self.pages[page_name] = page
#    Make the buttons from the page list provided
        self.create_buttons(container, self)

        self.show_page(str(self.p_names[0].__name__), self.currentPage)

    def show_page(self, page_name, button):
        self.currentPage.configure(relief="raised", bg="red", fg="black")
        page = self.pages[page_name]

#    Put the page in row 1 below the buttons, in the top left. Expand it so it fills the remainder of the cell/window
        #page.pack(side="top", fill="both", expand="true") #This line will cause error when uncommented.
        page.grid(row=1, columnspan=len(self.pages), sticky="nw")

        for p in self.pages:
            if p != page_name:
                self.pages[p].grid_forget()
        button.configure(relief="sunken", bg="black", fg="white")
        self.currentPage = button

    def create_buttons(self, s, controller):
        pgs = len(self.p_names)*3
#    need to figure out how to accurately get window width and use it properly for button width division
        pages = {}

        for i,p in enumerate(self.p_names):
            pages[i] = tk.Button(s, text=p.__name__.strip("Page"), fg="Black", bg="red",
                                 width=(self.winfo_reqwidth() // pgs) + 1,
                                 command=lambda i=i, p=p: controller.show_page(p.__name__, pages[i]))
            pages[i].grid(row=0, column=i)
        self.currentPage = pages[0]


class NewPage(tk.Frame):
    def __init__(self, parent, controller, title):
        self.title = title
        tk.Frame.__init__(self, parent, bg="Black")
        self.controller = controller

#    Create Page Title Label
        pageTitle = tk.Label(self, text=self.title, font=controller.title_font, bg="Black", fg="white")
#    Attempt to fill cell that page is in
        pageTitle.pack(fill="both", expand="true")
        pageTitle.grid_columnconfigure(1, weight=1)
        pageTitle.grid_rowconfigure(1, weight=1)
#    Pad the page title
        pageTitle.grid(row=0, column=0, pady=10, padx=10, sticky="nsew")


        #extraLabel = tk.Label(self, text="test", bg="blue")
        #extraLabel.grid(row=1, column=1, pady=5, padx=5, sticky="nsew")


class CharacterPage(NewPage):
    def __init__(self, parent, controller, title):
        super().__init__(parent, controller, title)


class OptionsPage(NewPage):
    def __init__(self, parent, controller, title):
        super().__init__(parent, controller, title)


class InventoryPage(NewPage):
    def __init__(self, parent, controller, title):
        super().__init__(parent, controller, title)


class RandomPage(NewPage):
    def __init__(self, parent, controller, title):
        super().__init__(parent, controller, title)


def main():
    app = Application("Game Title Here", [CharacterPage, InventoryPage, OptionsPage])
    app.mainloop()


main()

应该发生的是页面,因为它的背景是黑色的,应该覆盖黑色的单元格/窗口的其余部分。着色是为了让我直观地看到它正在工作,而不仅仅是让背景变黑。该页面最终将填充其他元素。

我是否缺少有关包或网格的内容?我对使用它们还很陌生。大约一周或两周。 在嵌套框架填充方面找不到任何内容。

【问题讨论】:

    标签: python tkinter


    【解决方案1】:

    您不能在同一个容器中使用 pack 和 grid。

    尝试为页面设置不同的背景颜色,以便您在看到它时知道:

    class NewPage(tk.Frame):
        def __init__(self, parent, controller, title):
            self.title = title
            tk.Frame.__init__(self, parent, bg="tan")    # bg='tan'
    

    您会看到页面位于左上角。在中间或页面中是标签pageTitle

    使用sticky="nwse" 扩展页面以填充单元格。

    【讨论】:

    • 左上角是想要的位置。问题是页面没有扩展以填充该区域。该页面应填充单元格的其余部分。容器是红色的,我可以说它正确地填充了窗口,因为背景变成了红色。页面背景为黑色。我可以说它没有填满它的剩余区域,因为页面仍然是红色的,而只有标签区域(页面标题)是黑色的。我最初将sticky="ne" 设置为sticky="nsew" 将它放在中间。即使那样,它也没有填满。
    • 另外,请注意,我可以先使用 pack,然后在建立容器后立即使用 grid configure。这不应该发生吗?
    • 我认为您将页面内的标签误认为是页面。试试我的新建议。
    • 即使打包也可以为grid配置frame。
    • 啊,我明白了我忽略了什么。谢谢你指出这一点。为了让阅读此内容的人更清楚一点:在第 66 行,我将框架设置为与标签相同的颜色,每当我试图将标签与页面区分开来时,我都会误入歧途。所以我们把我的页面背景变成了棕褐色。然后在第 42 行,由于我之前的误导,我对如何操作标签和页面的想法出现了偏差。我把页面放在左上角,以为它会用包填满页面。把它粘在所有方向上都可以解决这个问题。