了解在OOP中何时使用类与方法-使用tkinter切换框架



我正试图根据这里的答案/问题复制一个答案:在tkinter 中的两个帧之间切换

正如你从上面的答案中看到的,我们实例化了Frame小部件的多个子类,当我们想要切换页面时,我们点击一个按钮,该类是基类中的一个方法。

然而,在一个"pages"类下创建多个"pages"方法不是更干净、更有意义吗?我不知道该相信什么,我希望澄清我应该如何处理这个项目,以及为什么使用类或实例化方法会更好?

我已经在下面的代码中添加了我不太理解的行的注释,我希望我能从StackOverflow的世界中获得一些知识。

import Tkinter as tk
LARGE_FONT = ("Verdana", 12)
class Main(tk.Tk):
def __init__(self, *args, **kwargs):
########### are we calling the Tk class from tkinter and passing in our 'Main' class?
tk.Tk.__init__(self, *args, **kwargs)
# why not self.container?
container = tk.Frame(self)
# again, should I be using self.page here instead?
page = Pages(parent=container, controller=self)
container.pack(side="top", fill="both", expand=True)
container.grid_rowconfigure(0, weight=1)
container.grid_columnconfigure(0, weight=1)
self.frames = {}
for F in ('page.page_one()', 'page.page_two()'):
# what exactly does __name__ do? And how can I replicate this with my derived classes instanced methods?
page_name = F#F.__name__
frame = page#(parent=container, controller=self)
self.frames[page_name] = frame
frame.grid(row=0, column=0, sticky='nsew')
self.show_frame("page.page_one()")
def show_frame(self, page_name):
frame = self.frames[page_name]
frame.tkraise()
class Pages(tk.Frame):
# i could just use *args, **kwargs here couldn't I?
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.controller = controller
self.page_one(controller)
# here I have my instance methods inside my derived 'Pages' class
# isn't this much cleaner, having multiple instance methods inside a class?
# or I should be separating each page into it's own instanced class?
def page_one(self, controller):
label = tk.Label(self, text='show_firmware_page', font=LARGE_FONT)
label.pack(pady=10, padx=10)
# how can I switch pages using the next button?
next_btn = tk.Button(self, text='Next', command=lambda: controller.show_frame(self.page_two(controller)))
quit_btn = tk.Button(self, text='Quit', command=lambda: controller.show_frame())
quit_btn.pack()
next_btn.pack()
def page_two(self, controller):
label = tk.Label(self, text='second_page', font=LARGE_FONT)
label.pack(pady=10, padx=10)
# how can I switch pages using the next button?
next_btn = tk.Button(self, text='Next', command=lambda: Pages.show_frame("page_one"))
quit_btn = tk.Button(self, text='Quit', command=lambda: Pages.show_frame())
quit_btn.pack()
next_btn.pack()

app = Main()
app.mainloop()

基本上,我目前的努力是尝试使用类中的方法来定义我的页面并在它们之间切换。我目前遇到了一些麻烦,在查看其他人的答案后,他们中的很多人都认为每个类都实例化了一个Frame,在其中我们调用一个方法来在这些实例之间切换。

让我知道你对这个过程的想法,让我了解我应该如何处理这个项目。

非常感谢你的帮助——我真的很想把OOP的东西记下来。

理论上,您可以在一个类中创建方法,以您想要的方式重新配置UI,但这可能并不容易。

您当前的代码无法工作,因为您的一个方法没有简单的方法来清理以前另一个方法所做的工作(例如,通过去掉它创建的标签和按钮(。

您链接到的原始答案通过在程序开始时创建所有小部件(不仅仅是在它们即将显示时(来避免这个问题。不过,一次只显示一个页面,因为它们都是配置为显示在同一位置的框架。位于顶部的Frame隐藏其他控件,并阻止它们的小部件执行任何操作。通过在顶部移动不同的框架,您可以在页面之间切换。

如果我们忽略这些小部件显示问题,您可以让您的主类调用您编写的方法:

class Main(tk.Tk):
def __init__(self, *args, **kwargs):
container = tk.Frame(self) # I'm not sure a separate container is necessary
container.pack(side="top", fill="both", expand=True)  # since we're only putting 
container.grid_rowconfigure(0, weight=1)              # one other frame inside it
container.grid_columnconfigure(0, weight=1)
page = Pages(parent=container, controller=self)
page.grid(row=0, column=0, sticky='nsew') # moved up from below
self.frames = {}
for F in (page.page_one, page.page_two): # no quotes or parentheses
page_name = F.__name__ # the names are the strings "page_one" and "page_two"
self.frames[page_name] = F
self.show_frame("page_one")
def show_frame(self, page_name):
method = self.frames[page_name]
method() # call the method we are switching to
class Pages(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.controller = controller
def page_one(self):
# do something to clean up previous pages here?
label = tk.Label(self, text='show_firmware_page', font=LARGE_FONT)
label.pack(pady=10, padx=10)
next_btn = tk.Button(self, text='Next',
command=lambda: self.controller.show_frame("page_two")
next_btn.pack()
def page_two(self):
label = tk.Label(self, text='second_page', font=LARGE_FONT)
label.pack(pady=10, padx=10)
next_btn = tk.Button(self, text='Next',
command=lambda: self.controller.show_frame("page_one"))
next_btn.pack()

这将起作用(对于"工作"的某些定义(。我删除了退出按钮,因为我不确定处理它们的最佳方式是什么(您可能不希望它们调用show_frame(。

请注意,我绝不是TKinter的专家,所以当你进入下一个页面时,完全有可能有一些简单的方法从上一个页面中删除小部件。我只是不知道怎么做。

最新更新