首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >tkinter和GUI编程方法

tkinter和GUI编程方法
EN

Stack Overflow用户
提问于 2011-10-16 04:51:53
回答 1查看 3.4K关注 0票数 3

希望这不属于“一般性讨论主题”的范畴,因为我希望更多的是以有效的方式解决这些问题,而不是就GUI编程的哪一种一般方法是绝对最好的进行一场巨大的辩论。

所以我已经用tkinter和长话短说开始了一些GUI编程,我的代码很快就变得很难看了。我正试图为一个电子游戏创建一个基于瓷砖的地图编辑器。我的主要问题似乎是:

  1. 回调不能返回值。
  2. 不能轻松地在窗口之间传输数据。

我认为,我之所以将这些问题视为问题,是因为我使用的函数比使用类的要多得多。例如,我的“loads”窗口完全按功能处理:单击主窗口中的菜单选项将调用加载新窗口的函数。在该窗口中,我在查找图像时创建一个打开的文件对话框,并修改画布,当我按enter键时显示图像(以便它在图像上绘制适当的网格)。函数函数函数

在我看来,真正糟糕的做法是加入额外的论据来进行补偿。例如,当我创建一个tileset时,创建的TileSet类的实例应该被发送回主窗口,在那里可以显示适当的信息。我有一个作为全局变量的加载项集列表(更糟糕的做法是:处理根窗口的所有内容都在全局范围内!)),而且因为回调函数不返回值,所以我将该列表作为参数传递给我的“”函数,该函数随后将该参数传递给create函数(当您单击窗口中的适当按钮时调用),该函数是实际需要的,这样我就可以将新创建的tileset添加到列表中。像这样通过函数“层次”传递参数似乎是个可怕的想法。它会让人感到困惑,编写模块化代码是很可怕的,只是一般情况下似乎没有必要。

我解决这个问题的尝试是编写一个表示整个GUI的类,以及定制的窗口类( GUI类可以创建和引用),这些类实际上可以存储相关的数据。这应该可以解决在窗口之间传输数据的问题。希望它能减少我在回调中不必要地使用lambda函数。但我想知道:这是最好的方法吗?或者至少近一点?我不希望开始重写,然后以另一个系统结束,这个系统只是以一种不同的方式变得杂乱无章。我知道我的方法很糟糕,但我不知道最好的方法是什么。我得到了很多关于如何做具体事情的建议,但没有一个是关于如何把程序作为一个整体来组织的。任何帮助都将不胜感激。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2011-10-16 14:10:59

听起来,您正在尝试创建一个按程序执行的GUI,但这是行不通的。GUI不是过程性的,它们的代码不会在函数调用返回值的回调时线性运行。你所要求的并不是特征者独有的。这是基于事件的GUI编程的本质--回调不能返回任何东西,因为调用者是一个事件而不是函数。

粗略地说,您必须使用某种全局对象来存储数据。这通常被称为“模型”。它可以是全局变量,也可以是数据库,也可以是某种对象。无论如何,它必须存在于“全局”;也就是说,它必须对整个GUI都是可访问的。

通常,这种访问由称为"Controller“的第三个组件提供。它是GUI ( "View")和数据(“模型”)之间的界面。这三个组件构成了所谓的模型-视图-控制器模式,或MVC。

模型、视图和控制器不必是三个不同的对象。通常,GUI和控制器是同一个对象。对于小型程序来说,这很好-- GUI组件直接与您的数据模型对话。

例如,您可以有一个表示从Tkinter.Toplevel继承的窗口的类。它可以有一个表示正在编辑的数据的属性。当用户从主窗口中选择"New“时,它会执行类似于self.tileset = TileSet(filename)的操作。也就是说,它将名为self的GUI对象的名为self的属性设置为特定于给定文件名的TileSet类的实例。以后,操纵数据的函数使用self.tileset访问对象。对于驻留在主窗口对象之外的函数(例如,主窗口中的“保存所有”函数),您可以传递这个对象作为参数,或者使用window对象作为控制器,要求它对其tileset做一些事情。

下面是一个简单的例子:

代码语言:javascript
复制
import Tkinter as tk
import tkFileDialog
import datetime

class SampleApp(tk.Tk):
    def __init__(self, *args, **kwargs):
        tk.Tk.__init__(self, *args, **kwargs)
        self.windows = []
        menubar = tk.Menu(self)
        self.configure(menu=menubar)
        fileMenu = tk.Menu(self)
        fileMenu.add_command(label="New...", command=self.new_window)
        fileMenu.add_command(label="Save All", command=self.save_all)
        menubar.add_cascade(label="Window", menu=fileMenu)
        label = tk.Label(self, text="Select 'New' from the window menu")
        label.pack(padx=20, pady=40)

    def save_all(self):
        # ask each window object, which is acting both as 
        # the view and controller, to save it's data
        for window in self.windows:
            window.save()

    def new_window(self):
        filename = tkFileDialog.askopenfilename()
        if filename is not None:
            self.windows.append(TileWindow(self, filename))

class TileWindow(tk.Toplevel):
    def __init__(self, master, filename):
        tk.Toplevel.__init__(self, master)
        self.title("%s - Tile Editor" % filename)
        self.filename = filename
        # create an instance of a TileSet; all other
        # methods in this class can reference this
        # tile set
        self.tileset = TileSet(filename)
        label = tk.Label(self, text="My filename is %s" % filename)
        label.pack(padx=20, pady=40)
        self.status = tk.Label(self, text="", anchor="w")
        self.status.pack(side="bottom", fill="x")

    def save(self):
        # this method acts as a controller for the data,
        # allowing other objects to request that the 
        # data be saved
        now = datetime.datetime.now()
        self.status.configure(text="saved %s" % str(now))

class TileSet(object):
    def __init__(self, filename):
        self.data = "..."

if __name__ == "__main__":
    app = SampleApp()
    app.mainloop()
票数 8
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/7782425

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档