Python 3.x 使用类在tkinter中切换窗口

Python 3.x 使用类在tkinter中切换窗口,python-3.x,tkinter,Python 3.x,Tkinter,在[前一个问题][1]中,从@acw1668收到了创建弹出窗口的完美脚本(见下文) 如何将其改写为新窗口不是弹出窗口而是从一个页面切换到下一个页面的形式(此处不一定需要列表框/candva) 编辑:试图根据@Bryan Oakley的建议修改代码。 我的问题是:我无法将列表lst从GUI类传递到其他页面类,而不会出现错误消息: File "/.spyder-py3/temp.py", line 25, in __init__ frame = F(parent=container, co

在[前一个问题][1]中,从@acw1668收到了创建弹出窗口的完美脚本(见下文)

如何将其改写为新窗口不是弹出窗口而是从一个页面切换到下一个页面的形式(此处不一定需要列表框/candva)

编辑:试图根据@Bryan Oakley的建议修改代码。 我的问题是:我无法将列表
lst
GUI
类传递到其他页面类,而不会出现错误消息:

 File "/.spyder-py3/temp.py", line 25, in __init__
    frame = F(parent=container, controller=self)

TypeError: __init__() missing 1 required positional argument: 'lst'
我错过了什么? 我不明白这里发生了什么:

for F in (StartPage, PageOne, PageTwo):
                page_name = F.__name__
                frame = F(parent=container, controller=self,)

                self.frames[page_name] = frame
请有人解释一下好吗

import tkinter as tk
from tkinter import ttk


class GUI(tk.Tk):

    def __init__(self):

        tk.Tk.__init__(self)
        self.lst = ['a', 'b', 'c']
        container = tk.Frame(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 (StartPage, PageOne, PageTwo):
            page_name = F.__name__
            frame = F(parent=container, controller=self,)

            self.frames[page_name] = frame

            # put all of the pages in the same location;
            # the one on the top of the stacking order
            # will be the one that is visible.
            frame.grid(row=0, column=0, sticky="nsew")

        self.show_frame("StartPage", self.lst)

    def show_frame(self, page_name):
        '''Show a frame for the given page name'''
        frame = self.frames[page_name]
        frame.tkraise()


    def show_popup(self, page, lst):

        win = page(self, lst)
        win.grab_set()          # make window modal
        self.wait_window(win)   # make window modal




class StartPage(tk.Frame):

    def __init__(self, parent, controller, lst):
        tk.Frame.__init__(self, parent)
        self.controller = controller
        self.lst = lst
         # ------------------------------------------------------------------- #
        label = tk.Label(self, text="Check this out")                         
        label.pack(pady=10,padx=10)

         # ------------------- create buttons ---------------------------------
        button1 = ttk.Button(self, text="show all",
                             width = 25, command=lambda: 
                                 controller.show_popup(App, self.lst))
        button1.pack(pady=10, padx=10)        
        button2 = ttk.Button(self, text="show page one",
                             width = 25, command=lambda: 
                                 controller.show_frame(PageOne))
        button2.pack(pady=10, padx=10)        


class PageOne(tk.Frame):

    def __init__(self, parent, controller):
        tk.Frame.__init__(self, parent)
        self.controller = controller
        label = tk.Label(self, text="This is page 1")
        label.pack(side="top", fill="x", pady=10)
        button = tk.Button(self, text="Go to the start page",
                           command=lambda: controller.show_frame("StartPage"))
        button.pack()


class PageTwo(tk.Frame):

    def __init__(self, parent, controller):
        tk.Frame.__init__(self, parent)
        self.controller = controller
        label = tk.Label(self, text="This is page 2")
        label.pack(side="top", fill="x", pady=10)
        button = tk.Button(self, text="Go to the start page",
                           command=lambda: controller.show_frame("StartPage"))
        button.pack()

class App(tk.Toplevel):

    def __init__(self, parent, lst):
        tk.Toplevel.__init__(self, parent)
        self.lst = lst
        self.title('This is the pop up window')
        self.geometry('400x200') 
        label = tk.Label(self, text=self.lst) 
        label.pack(side="top", fill="x", pady=10)
        parent.grid_rowconfigure(0, weight = 1)
        parent.grid_columnconfigure(0, weight = 1)

if __name__ == '__main__': 
    app = GUI() 
    app.mainloop()                  

  [1]: http://stackoverflow.com/questions/41181809/how-to-open-and-close-another-window-with-scrollbar-in-tkinter-for-python-3-5/41182843?noredirect=1#comment69580999_41182843

您的类初始值设定项定义如下:

class StartPage(tk.Frame):
    def __init__(self, parent, controller, lst):
为了创建此类的实例,它需要三个参数(加上
self
):
parent
controller
lst

现在,让我们看看如何创建实例:

frame = F(parent=container, controller=self,)
请注意,您是如何拥有
父级
控制器
,但您还没有为
lst
传递任何内容。这就是为什么错误状态为“缺少1个必需的位置参数:'lst'”——因为您实际上缺少一个名为“lst”的必需参数

要解决此问题,只需提供此额外参数。例如:

frame = F(parent=container, controller=self, lst=self.lst)
class SomePage(tk.Frame):
    def __init__(self, parent, controller):
        self.controller = controller
        ...
    def some_function(self):
        print("The value of 'lst' is:", self.controller.lst)
然而,你可能不应该这样做。您复制的这一小块代码的体系结构使您可以从任何“页面”类访问GUI类上的值,而无需做任何额外的工作

由于此变量是
GUI
类的一个属性,并且您正在将对
GUI
类实例的引用传递到每个“页面”(
controller
属性),因此您可以随时访问此数据,而无需在构建时传入。您可以从
\uuuuu init\uuuuu
和创建页面的位置删除它(即:在修改之前返回原始代码),然后只要在需要值时使用
self.controller.lst

例如:

frame = F(parent=container, controller=self, lst=self.lst)
class SomePage(tk.Frame):
    def __init__(self, parent, controller):
        self.controller = controller
        ...
    def some_function(self):
        print("The value of 'lst' is:", self.controller.lst)

如果不需要弹出窗口,请不要从
tk.Toplevel
继承。在这里开始您的研究:我已经这样做了,但我没有设法使我的代码适应您链接的代码。在我的示例中,类GUI也是/已经是“起始页”。我无法集成/涉及其他页面类。有什么提示吗?
tk.Toplevel
用于创建第二个/第三个/etc.窗口-因此您必须使用不同的东西-即
tk.Frame
。你们需要一种方法来改变页面——迟早你们会在@BryanOakley链接中创建类似代码的东西。如果
StartPage
在单独的类中,而不是在GUI中,则会更容易。错误会准确地告诉您出了什么问题。您已经定义了
StartPage
需要一个列表参数,但您没有将列表参数传递给它。我不知道lst应该是什么,但是如果你想让一个类需要它,你必须在构造参数时包含它。确切地说,我只是不知道代码的哪一部分,我必须这样做。lst只是不同页面中需要的一些信息。非常感谢@Bryan Oakly。
self.controller.lst
中的
controller
是缺少的链接。我仍然很难使用和思考
parent
controller
术语。顺便说一句,我在前面尝试过
frame=F(parent=container,controller=self,self.lst)
,但正如您所说的,这是不对的,这也产生了一个错误
SyntaxError:positional参数跟在关键字参数之后
。是否可以从GUI类中的菜单栏命令调用页面类?我注意到这并没有像预期的那样起作用(如果菜单在GUI中,页面类会自动加载,并且页面类会被调用,比如
show\u popup(App,self.lst)
)@Al\u Iskander是的,当然可以从菜单栏命令调用页面类。菜单栏项可以调用与其他项相同的函数。你可能会发现这很有用:我不理解你的评论。这段代码除了在循环中创建实例之外,并没有做任何异常的事情。如果需要,可以删除循环(例如:
self.frames[“PageOne”]=PageOne(…)
)。除此之外,它只是普通的python类和对象。你可以随心所欲地传递变量——在函数调用中,在创建对象时,作为全局变量,等等。@Al_Iskander:我已经更新了,展示了如何单独初始化每个类,以防有帮助。