Python 框架未在tkinter中相互堆叠

Python 框架未在tkinter中相互堆叠,python,tkinter,Python,Tkinter,在tkinter中,我无法将“页面”堆叠在彼此的顶部 我有一个主帧,它包含两个子帧,两个子帧都包含不同的信息。第一个子帧包含一个列表框和一对按钮,并打包在主帧的左侧。第二个框架应该包含不同的“页面”(现在两个),并让它们填满整个框架。 我的问题是,两个“页面”并排显示,而不是相互重叠 import tkinter as tk class Settings(tk.Tk): def __init__(self, master=None): tk.Tk.__init__(

在tkinter中,我无法将“页面”堆叠在彼此的顶部

我有一个主
,它包含两个子帧,两个子帧都包含不同的信息。第一个子帧包含一个
列表框
和一对按钮,并打包在主帧的左侧。第二个框架应该包含不同的“页面”(现在两个),并让它们填满整个框架。 我的问题是,两个“页面”并排显示,而不是相互重叠

import tkinter as tk


class Settings(tk.Tk):

    def __init__(self, master=None):
        tk.Tk.__init__(self, master)
        self.focus_force()
        self.grab_set()
        # set focus to settings window
        # Main window title
        self.title("Settings")


        # set up grid containers
        container_main = tk.Frame(self, width=500, height=700)
        container_main.pack(side='top', fill='both', expand=True)
        container_main.grid_rowconfigure(0, weight=1)
        container_main.grid_columnconfigure(0, weight=1)

        container_listbox = tk.Frame(container_main, bg='blue', width=200, height=700)
        container_listbox.pack(side='left', fill='both', expand=True)
        container_listbox.grid_rowconfigure(0, weight=1)
        container_listbox.grid_columnconfigure(0, weight=1)

        container_settings = tk.Frame(container_main, bg='red', width=300, height=700)
        container_settings.pack(side='right', fill='both', expand=True)
        container_settings.grid_rowconfigure(0, weight=1)
        container_settings.grid_columnconfigure(0, weight=1)

        # build settings pages
        self.frames = {}

        self.frames["Options"] = Options(parent=container_listbox, controller=self)
        self.frames["General"] = General(parent=container_settings, controller=self)
        self.frames["Future"] = Future(parent=container_settings, controller=self)
如果我取消这两行的注释。我收到一个错误,说我无法在内部使用几何体管理器栅格

        # self.frames["General"].grid(row=0, column=0, sticky='nsew')
        # self.frames["Future"].grid(row=0, column=0, sticky='nsew')

两个“页面”同时初始化和显示,这是有意义的。我只是不知道如何让一个上升到另一个,因为
frame.tkraise()
应该这样做,但不是这样。我还希望能够在页面或不在顶部的页面上执行
grid\u forget()
,以避免将来可能意外地将值输入到隐藏的入口框中

编辑:如果我注释掉“未来”页面,那么“常规”页面将占用整个框架空间,因此使用
grid\u forget()
我将得到相同的结果。我只是不知道我会在哪里,但
grid\u-forget()
然后我会在哪里重新配置或执行
grid()
调用

我的问题是,两个“页面”并排显示,而不是相互重叠

import tkinter as tk


class Settings(tk.Tk):

    def __init__(self, master=None):
        tk.Tk.__init__(self, master)
        self.focus_force()
        self.grab_set()
        # set focus to settings window
        # Main window title
        self.title("Settings")


        # set up grid containers
        container_main = tk.Frame(self, width=500, height=700)
        container_main.pack(side='top', fill='both', expand=True)
        container_main.grid_rowconfigure(0, weight=1)
        container_main.grid_columnconfigure(0, weight=1)

        container_listbox = tk.Frame(container_main, bg='blue', width=200, height=700)
        container_listbox.pack(side='left', fill='both', expand=True)
        container_listbox.grid_rowconfigure(0, weight=1)
        container_listbox.grid_columnconfigure(0, weight=1)

        container_settings = tk.Frame(container_main, bg='red', width=300, height=700)
        container_settings.pack(side='right', fill='both', expand=True)
        container_settings.grid_rowconfigure(0, weight=1)
        container_settings.grid_columnconfigure(0, weight=1)

        # build settings pages
        self.frames = {}

        self.frames["Options"] = Options(parent=container_listbox, controller=self)
        self.frames["General"] = General(parent=container_settings, controller=self)
        self.frames["Future"] = Future(parent=container_settings, controller=self)
如果使用
pack()

根窗口和框架也是如此。如果
pack()
根窗口中有一个框架,则不能使用
grid()
将任何内容放入同一根窗口中

grid()
vs
pack()
问题的原因是类
General
和类
Future
配置标签小部件的位置是使用
pack()
的父框架。这防止了在同一父帧中使用
grid()
来放置常规帧和未来帧

要解决此问题,我们需要更改:

label = tk.Label(parent, text='General')

and

label = tk.Label(parent, text='Future')
致:

以上是此功能正常工作所需的唯一修复

import tkinter as tk


class Settings(tk.Tk):

    def __init__(self, master=None):
        tk.Tk.__init__(self, master)
        self.focus_force()
        self.grab_set()
        # set focus to settings window
        # Main window title
        self.title("Settings")

        container_main = tk.Frame(self, width=500, height=700)
        container_main.pack(side='top', fill='both', expand=True)
        container_main.grid_rowconfigure(0, weight=1)
        container_main.grid_columnconfigure(0, weight=1)

        container_listbox = tk.Frame(container_main, bg='blue', width=200, height=700)
        container_listbox.pack(side='left', fill='both', expand=True)
        container_listbox.grid_rowconfigure(0, weight=1)
        container_listbox.grid_columnconfigure(0, weight=1)

        container_settings = tk.Frame(container_main, bg='red', width=300, height=700)
        container_settings.pack(side='right', fill='both', expand=True)
        container_settings.grid_rowconfigure(0, weight=1)
        container_settings.grid_columnconfigure(0, weight=1)

        self.frames = {}

        self.frames["Options"] = Options(parent=container_listbox, controller=self)
        self.frames["General"] = General(parent=container_settings, controller=self)
        self.frames["Future"] = Future(parent=container_settings, controller=self)   


        self.frames["General"].grid(row=0, column=0, sticky='nsew')
        self.frames["Future"].grid(row=0, column=0, sticky='nsew')

    def show_frame(self, page_name):
        frame = self.frames[page_name]
        frame.tkraise()

class Options(tk.Frame):

    def __init__(self, parent, controller):
        tk.Frame.__init__(self, parent)
        self.controller = controller
        label = tk.Label(parent, text='List Box')
        label.grid(row=0, column=0, sticky='nsew', padx=1, pady=1)
        button1 = tk.Button(parent, text='General', command=lambda: controller.show_frame('General'))
        button2 = tk.Button(parent, text='Future', command=lambda: controller.show_frame('Future'))
        button1.grid(row=1, column=0, sticky='ew')
        button2.grid(row=2, column=0, sticky='ew')


class General(tk.Frame):
    def __init__(self, parent, controller):
        tk.Frame.__init__(self, parent)
        self.controller = controller
        label = tk.Label(self, text='General')
        label.pack(side='left', fill='both', expand=True)
        print("Hi I'm General")

class Future(tk.Frame):
    def __init__(self, parent, controller):
        tk.Frame.__init__(self, parent)
        self.controller = controller
        label = tk.Label(self, text='Future')
        label.pack(side='left', fill='both', expand=True)
        print("Hi I'm Future")

app = Settings()
app.mainloop()

我冒昧地重组了您的应用程序逻辑,以说明如何更容易地解决您的问题—我还提供了一些附加信息

当前实现的问题在于,它能够
隐藏
显示
您的页面,这是您为按钮分配的
命令
关键字。在我提供的实现中,
选项
类是所有神奇发生的地方,特别是
show_general
show_future
方法。简单地说,当单击常规按钮时,我在
future\u页面
小部件上调用
pack\u-forget()
,在
general\u页面
小部件上调用
pack(…)
,如果我想显示future页面,则反之亦然。(这个实现可以很容易地扩展,但我将让您自己决定。)

此外,我以模块化代码的方式构建了应用程序逻辑,因此在每个步骤中,我都可以测试它并查看我的位置,例如,我从
main()
开始创建每个容器,并确保所有内容都正确布局,(我喜欢给每个容器赋予不同的颜色,使其更容易显示间距等),然后转到
设置
选项
框架,在那里我将放置小部件,并编写GUI按预期运行所需的代码

我不会解释每一行,但我相信在这一点上,您可以看到我的意思。我建议您通读代码(从
main()
)开始, 我写这篇文章的目的是为了按照我相信你的意图发挥作用,并在这里和那里提供一些指导——这并不意味着完美


我希望这有帮助!

解决了
无法在
内部使用几何管理器网格的问题。我仍然需要一次只显示一个“页面”,例如减去for循环。您的第一个语句有点误导性。您可以在窗口中同时使用pack和grid,而不仅仅是使用共享一个共同父级的小部件。您的语句是almost使它听起来像是如果你在窗口中的任何地方使用pack,那么你就不能在任何地方使用grid,这是错误的。这可能是你在框架上使用pack的方式。@BryanOakley我想我的措辞是错误的。如果我错了,请纠正我,如果我在框架1中使用
pack()
,然后尝试使用
grid()
在frame1中,这应该会导致错误。我知道您可以在
frame1=Frame(root.pack()
上使用pack(),然后执行类似“entry=entry(frame1.grid)(row=0,column=0)”的操作,这样会很好地工作。@BryanOakley:我已经更新了对我的回答,在几何体管理器部分会更清楚。“您的思路是正确的,但是需要有某种方式来调用这两个小部件,以便显示一个小部件,隐藏一个小部件。“-这不是真的。如果两个小部件堆叠在一起,您只需将一个部件提升到另一个部件之上即可。@Flevincelming,非常感谢。我处理问题的方法与您处理颜色和模块化的方法相同。我只是在途中迷路了。合并
pack\u-forget()
也是我想要的,所以感谢您提供了一个简单而全面的示例。嘿,弗莱文克明。看看我的答案。您可能会惊讶于实际解决方案的简单程度。我花了几轮测试,但我找到了答案。@ernipeters很高兴您能找到答案。我只是更喜欢
pack
,但是还有
grid\u remove()
grid\u忘记()
import tkinter as tk


class Settings(tk.Tk):

    def __init__(self, master=None):
        tk.Tk.__init__(self, master)
        self.focus_force()
        self.grab_set()
        # set focus to settings window
        # Main window title
        self.title("Settings")

        container_main = tk.Frame(self, width=500, height=700)
        container_main.pack(side='top', fill='both', expand=True)
        container_main.grid_rowconfigure(0, weight=1)
        container_main.grid_columnconfigure(0, weight=1)

        container_listbox = tk.Frame(container_main, bg='blue', width=200, height=700)
        container_listbox.pack(side='left', fill='both', expand=True)
        container_listbox.grid_rowconfigure(0, weight=1)
        container_listbox.grid_columnconfigure(0, weight=1)

        container_settings = tk.Frame(container_main, bg='red', width=300, height=700)
        container_settings.pack(side='right', fill='both', expand=True)
        container_settings.grid_rowconfigure(0, weight=1)
        container_settings.grid_columnconfigure(0, weight=1)

        self.frames = {}

        self.frames["Options"] = Options(parent=container_listbox, controller=self)
        self.frames["General"] = General(parent=container_settings, controller=self)
        self.frames["Future"] = Future(parent=container_settings, controller=self)   


        self.frames["General"].grid(row=0, column=0, sticky='nsew')
        self.frames["Future"].grid(row=0, column=0, sticky='nsew')

    def show_frame(self, page_name):
        frame = self.frames[page_name]
        frame.tkraise()

class Options(tk.Frame):

    def __init__(self, parent, controller):
        tk.Frame.__init__(self, parent)
        self.controller = controller
        label = tk.Label(parent, text='List Box')
        label.grid(row=0, column=0, sticky='nsew', padx=1, pady=1)
        button1 = tk.Button(parent, text='General', command=lambda: controller.show_frame('General'))
        button2 = tk.Button(parent, text='Future', command=lambda: controller.show_frame('Future'))
        button1.grid(row=1, column=0, sticky='ew')
        button2.grid(row=2, column=0, sticky='ew')


class General(tk.Frame):
    def __init__(self, parent, controller):
        tk.Frame.__init__(self, parent)
        self.controller = controller
        label = tk.Label(self, text='General')
        label.pack(side='left', fill='both', expand=True)
        print("Hi I'm General")

class Future(tk.Frame):
    def __init__(self, parent, controller):
        tk.Frame.__init__(self, parent)
        self.controller = controller
        label = tk.Label(self, text='Future')
        label.pack(side='left', fill='both', expand=True)
        print("Hi I'm Future")

app = Settings()
app.mainloop()
import tkinter as tk

class Options(tk.Frame):

    def __init__(self, master):

        tk.Frame.__init__(self, master, bg='#FFFFFF', relief='ridge', bd=1)

        # Grab the 'Settings' tk.Frame object
        settings_frame = self.master.master.winfo_children()[1].winfo_children()[0]
        self.settings = settings_frame

        self.options()


    def options(self):
        self.label = tk.Label(self, text='List Box')
        self.button1 = tk.Button(self, text='General', command=self.show_general)
        self.button2 = tk.Button(self, text='Future', command=self.show_future)

        self.label.grid(row=0, sticky='nsew', padx=1, pady=1)  # column is set to 0 by default
        self.button1.grid(row=1, sticky='nsew', padx=1, pady=1)
        self.button2.grid(row=2, sticky='nsew', padx=1, pady=1)


    def show_general(self):
        self.settings.future_page.pack_forget()
        self.settings.general_page.pack(fill='both', expand=True)


    def show_future(self):
        self.settings.general_page.pack_forget()
        self.settings.future_page.pack(fill='both', expand=True)


class Settings(tk.Frame):

    def __init__(self, master):

        tk.Frame.__init__(self, master, bg='#FFFFFF', relief='ridge', bd=1)

        self.pages()


    def pages(self):
        self.general_page = tk.Label(self, fg='#FFFFFF', bg='#FF0000',
            relief='ridge', bd=1, text="Hi, I'm General.")
        self.future_page = tk.Label(self, fg='#FFFFFF', bg='#0000FF',
            relief='ridge', bd=1, text="Hi, I'm Future.")

        self.general_page.pack(fill='both', expand=True)


def main():
    root = tk.Tk()
    root.title('Settings')
    root.configure(bg='#DDDDDD', width=500, height=500)
    root.resizable(width=False, height=False)

    main_container = tk.Frame(root, bg='#FFFFFF', width=500, height=500)
    main_container.pack(fill='both', padx=20, pady=20)  # Add some padding to see container difference
    main_container.pack_propagate(False)  # Avoid sizing based on widget contents

    listbox_left = tk.Frame(main_container, bg='#4285F4', width=235)  # Take 15 from both sides for padding
    settings_right = tk.Frame(main_container, bg='#272727', width=235)

    listbox_left.pack(side='left', fill='y', padx=(10, 0), pady=10)
    listbox_left.pack_propagate(False)
    settings_right.pack(side='right', fill='y', padx=(0, 10), pady=10)
    settings_right.pack_propagate(False)

    settings = Settings(settings_right)  # Must be instantiated before Options
    options = Options(listbox_left)

    settings.pack(fill='both', expand=True, padx=2, pady=2)
    options.pack(fill='both', expand=True, padx=2, pady=2)

    root.mainloop()


if __name__ == '__main__':
    main()