【问题标题】:tkinter automatically loading windowtkinter 自动加载窗口
【发布时间】:2021-09-17 03:41:43
【问题描述】:

我在这里有这段代码,我想将值从一个类 (StartPage) 传递到另一个类 (PageOne)。我在我的控制器“get_page”中创建了一个方法,让我可以访问类之间的页面数据。所以,我在 StartPage 中有一个条目,我想将它的值传递给 PageOne。因此,代码运行,但在 PageOne 中有一个用于调试的打印。一旦我启动程序,它就会自动运行所有代码,就像调用 PageOne 一样,即使我没有按下按钮。我想传递给第二页的值永远不会被传递。有人可以帮我吗? 提前致谢!

 import tkinter as tk                # python 3
 from tkinter import font as tkfont
 from typing_extensions import IntVar  # python 3

class SampleApp(tk.Tk):

def __init__(self, *args, **kwargs):
    tk.Tk.__init__(self, *args, **kwargs)

    self.title_font = tkfont.Font(family='Helvetica', size=18, weight="bold", slant="italic")

    # the container is where we'll stack a bunch of frames
    # on top of each other, then the one we want visible
    # will be raised above the others
    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):
        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")

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

def get_page(self, classname):
    '''Returns an instance of a page given it's class name as a string'''
    for page in self.frames.values():
        if str(page.__class__.__name__) == classname:
            return page
    return None


class StartPage(tk.Frame):

def __init__(self, parent, controller):
    tk.Frame.__init__(self, parent)
    self.controller = controller
    label = tk.Label(self, text="Start Page: insert value", font=controller.title_font)
    label.pack(side="top", fill="x", pady=10)

    self.some_input = tk.StringVar()
    self.some_entry = tk.Entry(self, width=8) 
    self.some_entry.pack()
    self.some_input = self.some_entry.get()
    button1 = tk.Button(self, text='Next Page', command=lambda: controller.show_frame("PageOne"))
    button1.pack()

class PageOne(tk.Frame):

def __init__(self, parent, controller):
    tk.Frame.__init__(self, parent)
    self.controller = controller

    start_page = self.controller.get_page('StartPage')
    value = start_page.some_entry.get()
    print ('The value stored in StartPage entry = %s' % start_page.some_input)
    label = tk.Label(self, text="This is page 1, the value stored is" + str(value), font=controller.title_font)
    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()

if __name__ == "__main__":
app = SampleApp()
app.mainloop()

【问题讨论】:

  • 查看你的 for 循环:for F in (StartPage, PageOne) 然后frame = F(parent=container, controller=self)。这会在程序启动时同时创建StartPage()PageOne()。有 2 种可能的解决方案:创建一个 StartPage 调用的函数,在 PageOne 内创建标签,或者重新设计整个代码。
  • “一个开始页面调用的函数在第一页内创建标签”是什么意思?

标签: python class tkinter model-view-controller


【解决方案1】:

您需要找到一种方法来通知PageOne 以在show_frame() 显示标签时更新标签,其中一种方法是使用event_generate() 函数通过虚拟事件:

class SampleApp(tk.Tk):
    ...
    def show_frame(self, page_name):
        '''Show a frame for the given page name'''
        frame = self.frames[page_name]
        frame.tkraise()
        # notify frame that it is raised via virtual event
        frame.event_generate("<<Raised>>")

...
class PageOne(tk.Frame):

    def __init__(self, parent, controller):
        tk.Frame.__init__(self, parent)
        self.controller = controller
        # save a reference of 'StartPage'
        self.start_page = self.controller.get_page('StartPage')
        # use instance variable 'self.label' instead of local variable 'label'
        self.label = tk.Label(self, font=controller.title_font)
        self.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()

        # bind the virtual event
        self.bind("<<Raised>>", self.on_raised)

    def on_raised(self, event):
        self.label.config(text=f"This is page 1, the value stored is '{self.start_page.some_entry.get()}'")

【讨论】:

  • 谢谢,这行得通,除了在“on raise”中你必须使用“self.start_page.some_input.get()”这一事实。但我在想……在 PageOne 中继承起始页不是更容易吗?
  • 不,它应该是self.start_page.some_entry.get(),因为您已将some_input 重新分配给StartPage.__init__() 内的一个空字符串self.some_input = self.some_entry.get()。从StartPage 继承不是一个合适的设计。
  • 但是如果我使用self.some_input 它工作正常,如果我使用self.some_entry 我得到这个错误`AttributeError: 'NoneType' object has no attribute 'get'`
  • 那么您发布的代码与您使用的代码不同。您使用的代码可能类似于:self.some_entry = tk.Entry(...).pack().
  • @mandiatodos 根据 acw1668 的评论,您的代码很可能有 this 错误。
猜你喜欢
  • 2017-01-05
  • 1970-01-01
  • 1970-01-01
  • 2021-06-05
  • 1970-01-01
  • 2020-11-07
  • 2012-08-07
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多