【问题标题】:What is a parent/master that initialize a tkinter class?什么是初始化 tkinter 类的父/主?
【发布时间】:2020-03-19 06:42:54
【问题描述】:

注意

示例代码是精简版,但可以运行基本功能。请关注class MainWindow(tk.Frame)

问题

什么样的object可以起到parent or mastertkinter class初始化的作用?

在我的情况下,请参见示例代码,为什么不能将self 作为parent 传递给ProjectInfo(...)ConfirmItems(...) 中的class MainWindow(tk.Frame)?如果使用self 而不是self.parent,它会弹出一个空窗口。

参考

这个问题源于我在Best way to structure a tkinter application上的cmets,也就是说它无法通过self作为parent

我想提出一个新问题来跟进讨论。

import tkinter as tk
from tkinter import messagebox
from collections import OrderedDict

class ProjectInfo(tk.Frame):
    def __init__(self, parent, controller, *args, **kwargs):
        super().__init__(parent, *args, **kwargs)
        self.parent = parent
        self.controller = controller
        self.widgets_init()

    def widgets_init(self):
        tk.Label(self,
                    text = "Rock Controller!",
                    width = 10,
                    anchor = "w",
                    justify = "left").grid(row = 0, column = 0)
        tk.Label(self,
                    text = "Input Name: ").grid(row = 1, column = 0)
        self.entry = tk.Entry(self)
        self.entry.grid(row = 1, column = 1)

class ConfirmItems(tk.Frame):
    def __init__(self, parent, frames, controller, *args, **kwargs):
        super().__init__(parent, *args, **kwargs)
        self.parent = parent
        self.frames = frames
        self.controller = controller
        self.widgets_init()

    def update_entries(self):
        self.controller.project_info.name = self.controller.project_info.entry.get()

    def update_frames(self):
        self.message = 'Click Cancel go back to reset!\n'
        for key, values in self.frames.items():
            for v in values:
                x = getattr(key, v)
                self.message += v + ': ' + str(x) + '\n'

    def show_settings(self):
        answer = tk.messagebox.askokcancel("Check Settings", self.message)
        if answer in ["yes", 1]:
            self.quit()

    def combine_funcs(self, *funcs):
        def combined_func(*args, **kwargs):
            for f in funcs:
                f(*args, **kwargs)
        return combined_func

    def widgets_init(self):
        self.cancel = tk.Button(self,
                                text = "Cancel",
                                command = self.quit)
        self.cancel.grid(row = 0, column = 0)

        self.submit = tk.Button(self,
                                text = "Submit",
                                command = self.combine_funcs(
                                                            self.update_entries,
                                                            self.update_frames,
                                                            self.show_settings))
                                # command = lambda:[self.update_frames(), self.show_settings()]
        self.submit.grid(row = 0, column = 1)

class MainWindow(tk.Frame):
    def __init__(self, parent, *args, **kwargs):
        super().__init__(parent, *args, **kwargs)
        self.parent = parent
        self.controller = self

        self.project_info = ProjectInfo(self.parent, self.controller)
        self.project_info.grid(row = 0)
        self.widgets_init()

        self.confirm_items = ConfirmItems(self.parent, self.frames, self.controller)
        self.confirm_items.grid(row = 1)

    def widgets_init(self):
        self.dict_list = [(self.project_info, ('name',))]
        self.frames = OrderedDict(self.dict_list)

def main():
    root = tk.Tk()
    root.title("Welcome to Controller World!")
    root.geometry("300x300")
    gui = MainWindow(root)
    root.mainloop()

if __name__ == "__main__":
    main()

【问题讨论】:

  • 您没有布置MainWindow 对象,因此所有带有parent=self 的小部件都被隐藏了。

标签: python class tkinter initialization parent


【解决方案1】:

什么样的对象可以起到父类或主控的作用来进行tkinter类的初始化?

任何 tkinter 小部件都可以扮演父级或主控的角色,尽管它通常是根窗口、顶层窗口或框架。

在我的情况下,请参见示例代码,为什么不能将 self 作为父级传递给 MainWindow(tk.Frame) 类中的 ProjectInfo(...) 或 ConfirmItems(...)?

您的代码中没有任何内容阻止您将self 作为父级传递。

如果使用 self 而不是 self.parent 会弹出一个空窗口。

在使用self 作为ProjectInfo 的父级的情况下,self 指的是MainWindow 的实例。我看不到您在该实例上调用packgrid 的任何地方。如果父项不可见,则其子项均不可见。

您需要在gui 变量上调用packgrid。由于它被设计为根窗口中的唯一小部件,因此pack 最有意义。

def main():
    ...
    gui = MainWindow(root)
    gui.pack(side="top", fill="both", expand=True)
    ...

作为一般经验法则,如果您有一个从小部件继承的类并创建其他小部件,则这些小部件应始终是 self 或其后代之一的子级,而不是其自己的父级。让一个类将子小部件放在其父级中完全违背了从tk.Frame 继承的目的。

tk.Frame 继承的全部意义在于创建一个行为与标准小部件完全相同的新类。您可以使用packplacegrid 将其添加到其他小部件,它具有一些标准选项,例如borderwidthrelief,并且是完全独立的。

【讨论】:

  • 或者我可以在class MainWindow(tk.Frame)__init__(...)中添加一行self.grid(row = 0)。现在我进一步理解了为什么我们要创建tk.Frame 或其他标准小部件(如Toplevel)的子类。它是特定于应用程序的。我们只是将一些更自定义的结构/属性/函数包装到one self-contained Unit 中,它也继承了其parent 的属性。
  • @Kuo:自定义小部件类调用 gridpack 本身是一种不好的做法。作为一般经验法则,创建小部件的代码应该负责使其可见。但是,如果您愿意,没有什么可以阻止您这样做。
  • 你是对的。这是一个非常糟糕的做法。小部件本身无法提前知道它属于哪里。
猜你喜欢
  • 2016-11-04
  • 2011-04-28
  • 2022-01-03
  • 1970-01-01
相关资源
最近更新 更多