【问题标题】:Is this bad programming practice in tkinter?这是 tkinter 中不好的编程习惯吗?
【发布时间】:2014-10-16 17:22:19
【问题描述】:

我正在学习使用 tkinter 编写事件驱动程序,并且正在使用 Fredrik Lundh 的优秀教程。 在那,他提到最好为框架定义一个类(App)并将程序作为该类的实例运行,而不是像这样启动它:

root = Tk()
w = Label(root, text = 'hello, world!')
w.pack()
root.mainloop()

我有 3 个问题:

  1. 以这种更简单的方式来做是不好的编程习惯吗?

  2. 如果我确实定义了一个类,回调函数绑定到小部件,这些函数是否都必须在类本身内?即,我可以在类中设置一个显示 go 的按钮,当我单击该按钮时,它会运行在类外定义的详细例程?

  3. 然后将结果生成到类之外并在类中显示它是不好的做法吗?

基本上,我可以通过跳进跳​​出班级来使程序正常工作,但不确定这样做是否是不好的做法(例如全局变量)。

【问题讨论】:

    标签: python user-interface tkinter


    【解决方案1】:
    1. 随着应用程序变得越来越大,您将需要使用类。不必全神贯注于整个代码,您可以一次专注于一个类。
    2. 您不仅限于使用类中的方法。您的代码可能会利用外部函数或类来获取信息,甚至修改提供给它们的参数。
    3. 不,这可能是显示信息的方式。或者,您可以使用文件来输出结果,如果存在,也可以打印到控制台。

    示例:

    import tkinter
    import random
    
    class Application(tkinter.Frame):
    
        @classmethod
        def main(cls):
            root = tkinter.Tk()
            frame = cls(root)
            frame.grid()
            root.mainloop()
    
        def __init__(self, master=None, cnf={}, **kw):
            super().__init__(master, cnf, **kw)
            self.w = tkinter.Label(self, text='Hello, world!')
            self.w.grid()
            self.v = tkinter.Button(self, text='Press Me', command=self.click)
            self.v.grid()
            self.u = tkinter.Button(self, text='Me Too!',
                                    command=lambda: external_mutator(self.w))
            self.u.grid()
    
        def click(self):
            self.w['text'] = external_function(3)
    
    def external_function(ndigits):
        return round(random.random(), ndigits)
    
    def external_mutator(widget):
        widget['text'] = external_function(6)
        print('Hello to you too!')  # shown on console if present
    
    if __name__ == '__main__':
        Application.main()
    

    main 类方法的替代方法:

    import tkinter
    import random
    
    class Main(tkinter.Tk):
    
        def __init__(self, screenName=None, baseName=None, className='Tk',
                     useTk=1, sync=0, use=None):
            super().__init__(screenName, baseName, className,
                             useTk, sync, use)
            frame = Application(self)
            frame.grid()
            self.mainloop()
    
    class Application(tkinter.Frame):
    
        def __init__(self, master=None, cnf={}, **kw):
            super().__init__(master, cnf, **kw)
            self.w = tkinter.Label(self, text='Hello, world!')
            self.w.grid()
            self.v = tkinter.Button(self, text='Press Me', command=self.click)
            self.v.grid()
            self.u = tkinter.Button(self, text='Me Too!',
                                    command=lambda: external_mutator(self.w))
            self.u.grid()
    
        def click(self):
            self.w['text'] = external_function(3)
    
    def external_function(ndigits):
        return round(random.random(), ndigits)
    
    def external_mutator(widget):
        widget['text'] = external_function(6)
        print('Hello to you too!')  # shown on console if present
    
    if __name__ == '__main__':
        Main()
    

    【讨论】:

    • 恕我直言,用实例化它的类方法定义一个类,用两个词来说,很奇怪。
    • 我这样做有几个原因。 (1) 使用if __name__ == '__main__': 是可取的。 (2)检查后拨打main是典型的。 (3) 当应用程序与该类几乎没有任何关系时,让 main 构造一个根来运行该类似乎很奇怪。 (4) 由于应用程序作为一个整体在忽略子组件时通常是该类,因此似乎应该调用该类。 (5) 如果目标是引起对该课程的注意,将main 放在该课程中似乎是相当明智的。 (6) 该类仍可用作更大应用程序的组件。
    • 好的,听起来有道理。只是好奇,你发明了这项技术还是一种常见的做法(对于 tkinter 应用程序)?
    • 在开始使用类似于 user3353185 所呈现的简单、无组织的程序后,我逐渐迁移到使用类,发现代码更易于使用,但仍然保持main 函数来启动应用程序.一段时间后,我注意到了一种趋势:在一大堆类中使用一个函数,并且该函数有兴趣创建一个真正代表应用程序的类。所以我发明了将main 嵌入到类中的技术。一种替代方法是从 tkinter.Tk 继承并将 main 代码放在初始化程序中。
    【解决方案2】:
    1. 一般来说是的...对于较小的程序,这可能不会有太大问题,但随着复杂性的增加,将事物合并到类中会很好
    2. 是的
    3. 不是真的...(全局变量往往是不好的做法...)但您描述的是消息封装和传递

    【讨论】:

      【解决方案3】:

      1) 对于这个例子,我想说,它不一定是错的。程序运行。真正令人担心的是,当您开始制作更复杂的程序时,您可能需要更结构化的格式。课程可以提供帮助。

      2) 函数不必都在类本身内。方法可以调用外部函数。拥有方法而不是函数的主要原因是该方法可以随时访问对象的所有属性。您希望避免函数到达对象内部来操作属性。

      3) 将变量传递给类比定义全局变量更好,主要是因为它很难维护范围。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-06-27
        • 2021-07-17
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多