【问题标题】:Tkinter cross reference class and variables using controller?使用控制器的 Tkinter 交叉引用类和变量?
【发布时间】:2021-02-21 04:08:47
【问题描述】:

在我的previous post 中,我询问了如何在 Tkinter 中的类之间引用方法和变量。 @JacksonPro 使用 parent 提供了一个很好的解决方案,如下所示:

from tkinter import *
from tkinter import scrolledtext
    
    
def main():
        """The main app function"""
        root = Tk()
        root_window = Root(root)
        root.mainloop()
    
    
class Root:
    
        def __init__(self, root):
            # Main root window configration
            self.root = root
            self.root.geometry("200x100")
            
            self.btn_ok = Button(self.root, text="Open new window",
                                 command=lambda :NewWindow(self))
            self.btn_ok.pack(padx=10, pady=10)
    
        def hide(self):
            """Hide the root window."""
            self.root.withdraw()
    
        def show(self):
            """Show the root window from the hide status"""
            self.root.update()
            self.root.deiconify()
    
        def onClosing(self, window):
            window.destroy()
            self.show()
    
class NewWindow:
        
        def __init__(self, parent):
    
            self.parent = parent
            parent.hide()
        
            self.new_window = Toplevel()
    
            lbl = Label(self.new_window, text="Input here:")
            lbl.pack(padx=10, pady=(10, 0), anchor=W)
    
            # Create a scrolledtext widget.
            self.new_content = scrolledtext.ScrolledText(
                                    self.new_window, wrap=WORD,
                                    )
    
            self.new_content.pack(padx=10, expand=True, fill=BOTH, anchor=W)
    
    
            # Respond to the 'Cancel' button.
            btn_cancel = Button(self.new_window, text="Cancel", width=10,
                                command=lambda: parent.onClosing(self.new_window))
            btn_cancel.pack(padx=10, pady=10, side=RIGHT)
    
            # Add 'OK' button to read sequence
            self.btn_ok = Button(self.new_window, text="OK", width=10,
                                 command=self.readContent)
            self.btn_ok.pack(padx=10, pady=10, side=RIGHT)
    
        def readContent(self):
            self.content = self.new_content.get(1.0, END)
            
            self.new_window.destroy()
            workwindow = WorkingWindow(self)
            
    
    
class WorkingWindow:
    
        def __init__(self, parent):

            self.parent = parent
            self.work_window = Toplevel()
            self.work_content = scrolledtext.ScrolledText(self.work_window, wrap=WORD, font=("Courier New", 11))
            self.work_content.pack(padx=10, expand=True, fill=BOTH, anchor=W)
            self.work_content.insert(1.0, parent.content)
            self.work_window.protocol("WM_DELETE_WINDOW",
                             lambda: parent.parent.onClosing(self.work_window))
    
    
if __name__ == '__main__':
        main()

但是,这种方法似乎只允许您在类之间逐层引用,使用大量parent。代码中是这样的:

self.work_window.protocol("WM_DELETE_WINDOW", lambda: parent.parent.onClosing(self.work_window))

当类在应用程序中累积时会非常不方便和混乱。所以我想知道如何使用controller 实现从任何地方访问任何类中的任何方法或变量的目标?我在controller 上看到过帖子,但仍然对如何使用它感到困惑,例如,在这种情况下。任何帮助,将不胜感激。谢谢!

【问题讨论】:

  • 我发现将主(控制器)窗口向下传递到任何较低级别的小部件会更清晰,例如新窗口将是 def __init__(self,parent,controller,.... 这个控制器变量可以传递给层次结构中的较低类。它将框架/窗口与控制器功能分开,甚至允许您使用单独的类作为控制器。也就是说,控制器就是控制器。你不应该尝试直接与邻居通信。而是在控制器中定义函数来处理通信。
  • 如果您提供指向您正在查看的帖子的链接并解释该帖子令人困惑的地方,您的帖子会更清晰。

标签: python class tkinter reference controller


【解决方案1】:

由于每个 tk 对象都知道它们的主对象是什么,因此使用递归函数调用来查找作为 Tk 实例的父对象。

下面是一个人为的示例,其中包含几个不同的框架和一个按钮。 find_tkroot 函数将在层次结构中向上移动以找到 Tk 实例。在这种情况下,它只是使用它来设置根窗口的标题。

from tkinter import *

def find_tkroot(widget):
    try:
        if widget.__class__.__name__ == 'Tk':
            return widget
        else:
            return find_tkroot(widget.master)
    except RecursionError as err:
        print(err)
        print("Got lost at {0}".format(widget))

root = Tk()
frm1 = Frame(root)
frm2 = Frame(frm1)
frm1.grid()
frm2.grid()
btnClose = Button(frm2,text="Close",command=lambda: find_tkroot(btnClose).title('Set Me'))
btnClose.grid()

print(find_tkroot(frm2))

如果您创建自己的类,您可以扩展它以查找特定类名的父类。

def find_parent_matching(widget, class_name):
    print("Checking: ", widget)
    try:
        if widget.__class__.__name__ == class_name:
            return widget
        else:
            return find_tkroot(widget.master)
    except RecursionError as err:
        print(err)
        print("Got lost at {0}".format(widget))

将小部件名称作为第二个参数,例如find_parent_matching(widget,'MyCustomClass')

【讨论】:

    猜你喜欢
    • 2012-10-22
    • 2020-02-19
    • 2023-03-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-01-12
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多