构建tkinter应用程序的最佳方法

Chr*_*ung 115 python tkinter

以下是我典型的python tkinter程序的整体结构.

def funA():
    def funA1():
        def funA12():
            # stuff

    def funA2():
        # stuff

def funB():
    def funB1():
        # stuff

    def funB2():
        # stuff

def funC():
    def funC1():
        # stuff

    def funC2():
        # stuff


root = tk.Tk()

button1 = tk.Button(root, command=funA)
button1.pack()
button2 = tk.Button(root, command=funB)
button2.pack()
button3 = tk.Button(root, command=funC)
button3.pack()
Run Code Online (Sandbox Code Playgroud)

funA funB当用户点击按钮1,2,3时,funC将显示Toplevel带有小部件的另一个窗口.

我想知道这是否是编写python tkinter程序的正确方法?当然,即使我这样写,它也会起作用,但这是最好的方法吗?这听起来很愚蠢但是当我看到其他人编写的代码时,他们的代码并没有被大量的函数弄乱,而且大多数都有类.

我们应该遵循哪些具体结构作为良好做法?在开始编写python程序之前我应该​​如何计划?

我知道编程中没有最佳实践,我也不是要求它.我只是想要一些建议和解释,让我保持正确的方向,因为我自己学习Python.

Bry*_*ley 222

我提倡面向对象的方法.这是我开始使用的模板:

# Use Tkinter for python 2, tkinter for python 3
import tkinter as tk

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

        <create the rest of your GUI here>

if __name__ == "__main__":
    root = tk.Tk()
    MainApplication(root).pack(side="top", fill="both", expand=True)
    root.mainloop()
Run Code Online (Sandbox Code Playgroud)

需要注意的重要事项是:

  • 我不使用通配符导入.我将包导入为"tk",这要求我为所有命令添加前缀tk..这可以防止全局命名空间污染,而且当您使用Tkinter类,ttk类或您自己的某些类时,它会使代码完全明显.

  • 主要应用是一个类.这为您的所有回调和私有函数提供了一个私有命名空间,通常可以更轻松地组织您的代码.在程序风格中,你必须自上而下编码,在使用它们之前定义函数等.使用这种方法你不会因为你直到最后一步才创建主窗口.我更喜欢继承,tk.Frame因为我通常首先创建一个框架,但这绝不是必要的.

如果您的应用程序有额外的顶级窗口,我建议将每个窗口作为一个单独的类继承tk.Toplevel.这为您提供了上面提到的所有相同的优点 - 窗口是原子的,它们有自己的命名空间,代码组织得很好.此外,一旦代码开始变大,就可以轻松地将每个模块放入自己的模块中.

最后,您可能需要考虑为接口的每个主要部分使用类.例如,如果您要创建一个包含工具栏,导航窗格,状态栏和主区域的应用程序,则可以创建这些类中的每一个.这使您的主代码非常小并且易于理解:

class Navbar(tk.Frame): ...
class Toolbar(tk.Frame): ...
class Statusbar(tk.Frame): ...
class Main(tk.Frame): ...

class MainApplication(tk.Frame):
    def __init__(self, parent, *args, **kwargs):
        tk.Frame.__init__(self, parent, *args, **kwargs)
        self.statusbar = Statusbar(self, ...)
        self.toolbar = Toolbar(self, ...)
        self.navbar = Navbar(self, ...)
        self.main = Main(self, ...)

        self.statusbar.pack(side="bottom", fill="x")
        self.toolbar.pack(side="top", fill="x")
        self.navbar.pack(side="left", fill="y")
        self.main.pack(side="right", fill="both", expand=True)
Run Code Online (Sandbox Code Playgroud)

由于所有这些实例共享一个公共父级,因此父级实际上成为模型 - 视图 - 控制器体系结构的"控制器"部分.因此,例如,主窗口可以通过调用在状态栏上放置一些内容self.parent.statusbar.set("Hello, world").这允许您在组件之间定义一个简单的接口,有助于保持与最小化的耦合.

  • @Bryan Oakley你知道互联网上有什么好的样本代码可以研究它们的结构吗? (18认同)
  • @gcb:是的,任何类都会给你一个私有命名空间.为什么要为一个Frame子类化?我通常会创建一个框架,所以它只需要管理一个类(Frame的子类,一个继承自object的类,一个框架作为属性).我稍微改写了答案,以便更清楚.感谢您的反馈. (3认同)
  • 我第二种面向对象的方法。但是,根据我的经验,不要在调用GUI的类上使用继承是一个好主意。如果Tk和Frame对象都是不从任何东西继承的类的属性,则它将为您提供更大的灵活性。这样,您可以更轻松地(并且不那么模棱两可)访问Tk和Frame对象,并且如果不想破坏一个对象,也不会破坏它。我忘记了在某些程序中至关重要的确切原因,但是它确实允许您执行更多操作。 (2认同)
  • 这里的 OOP 方法很好而且很花哨(而且很琐碎),但是如何分配职责呢?哪个类应该负责创建每个小部件?哪个类应该负责以正确的方式布局它们?如何以不打破它们之间界限的方式管理控制器-gui 耦合? (2认同)
  • @madtyn:不需要保存对“ parent”的引用,除非您稍后要使用它。我没有保存它,因为示例中的任何代码都不需要保存它。 (2认同)

ale*_*cxe 31

将每个顶级窗口放入其自己的独立类中,可以让您重复使用代码并更好地进行代码组织.应在此类中定义窗口中存在的任何按钮和相关方法.这是一个例子(取自这里):

import tkinter as tk

class Demo1:
    def __init__(self, master):
        self.master = master
        self.frame = tk.Frame(self.master)
        self.button1 = tk.Button(self.frame, text = 'New Window', width = 25, command = self.new_window)
        self.button1.pack()
        self.frame.pack()
    def new_window(self):
        self.newWindow = tk.Toplevel(self.master)
        self.app = Demo2(self.newWindow)

class Demo2:
    def __init__(self, master):
        self.master = master
        self.frame = tk.Frame(self.master)
        self.quitButton = tk.Button(self.frame, text = 'Quit', width = 25, command = self.close_windows)
        self.quitButton.pack()
        self.frame.pack()
    def close_windows(self):
        self.master.destroy()

def main(): 
    root = tk.Tk()
    app = Demo1(root)
    root.mainloop()

if __name__ == '__main__':
    main()
Run Code Online (Sandbox Code Playgroud)

另见:

希望有所帮助.


Ser*_*ial 5

这不是一个坏结构。它会很好地工作。但是,当某人单击按钮或其他内容时,您必须在函数中具有执行命令的功能

因此,您可以为它们编写类,然后在该类中具有处理按钮单击等命令的方法。

这是一个例子:

import tkinter as tk

class Window1:
    def __init__(self, master):
        pass
        # Create labels, entries,buttons
    def button_click(self):
        pass
        # If button is clicked, run this method and open window 2


class Window2:
    def __init__(self, master):
        #create buttons,entries,etc

    def button_method(self):
        #run this when button click to close window
        self.master.destroy()

def main(): #run mianloop 
    root = tk.Tk()
    app = Window1(root)
    root.mainloop()

if __name__ == '__main__':
    main()
Run Code Online (Sandbox Code Playgroud)

通常带有多个窗口的tk程序是多个大类,并且在__init__所有条目中创建标签等,然后每种方法都将处理按钮单击事件

只要有可读性,实际上就没有正确的方法,只要它对您有用并且可以完成工作,并且您可以轻松地解释它,因为如果您不能轻松地解释您的程序,那么可能会有更好的方法。

看一看《Tkinter中的思考》

  • “在Tkinter中思考”提倡全球进口,我认为这是非常糟糕的建议。 (3认同)