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