在不同的类中传送tkinter按钮的执行?

时间:2015-10-14 06:43:16

标签: python python-3.x tkinter

我有一个使用tkinter的简单图形用户界面,它提供了一个空白画布,光标在任意位置放置绿色方块。

我正在尝试在界面顶部的“全部清除”按钮中编码,清除整个画布(同时保持光标在再次点击画布时绘制正方形的能力) :

import tkinter as tk 

class Interface(tk.Frame):
    def __init__(self, master):
        super().__init__(master)
        tk.Button(self, text="Clear all", command=self.clearall).pack(side = tk.LEFT)

    #What the heck do I do here?
    def clearall(self):
        #self._canvas.delete(tk.ALL)
        pass

class App(object):
    def __init__(self, master):
        master.title("Doodle test")
        master.geometry("600x600")
        self._interface = Interface(master)
        self._interface.pack()
        self._canvas = tk.Canvas(master, bg='white')

        self._canvas.pack(fill=tk.BOTH, expand=1)
        self._canvas.bind("<Button-1>", self.leftclick)

    # And would I need to put something here?
    def plz_run_me_when_clearall_method_is_called(self):
        self._canvas.delete(tk.ALL)

    def leftclick(self, arg):
        d = 10
        self._canvas.create_rectangle([(arg.x, arg.y), (arg.x+d, arg.y+d)], fill="green")


root = tk.Tk()
app = App(root)
root.mainloop()

通常,如果整个程序是在一个类中构造的,那么这将是一个简单的任务,例如:

def clearall(self):
    self._canvas.delete(tk.ALL)

由于有两个类,我无法为.delete(tk.ALL)调用_canvas方法,因为它是在App类中声明的。那么我怎么能传达一个按钮来执行从另一个类影响项目Y的函数X?

编辑:仍然试图为这篇文章考虑一个合适的标题。

1 个答案:

答案 0 :(得分:2)

python(不仅仅是tkinter)的一个简单规则是,如果一个对象需要另一个对象中的资源,那么第一个对象需要对第二个对象的引用。

这意味着要么将App的实例传递给Interface的实例,要么传递画布本身。

使用紧耦合

例如,您可以通过这种方式传递画布:

class Interface(tk.Frame):
    def __init__(self, master, canvas):
        ...
        self._canvas = canvas
        ...
    def clearall(self):
        self._canvas.delete(tk.ALL)


class App(object):
    def __init__(self, master):
        ...
        self._canvas = tk.Canvas(master, bg='white')
        self._interface = Interface(master, self._canvas)
        ...

有许多方法可以完成类似的事情。例如,您可以传递对应用程序本身的引用(例如:self._interface = Interface(master, self). You could then either make self._canvas`“public”,或者您可以提供返回画布的getter,而不是传入画布。

上述方法的潜在缺点是它将两个类紧密地联系在一起。也就是说,如果有一天App被重新绘制在图像对象而不是画布对象上,则Interface也必须进行修改,因为它取决于App中的特定实现(也就是说,它在画布上完成所有工作。)

使用松耦合

松散耦合意味着Interface不了解或关心App的实施方式,它只知道App承诺提供Interface可以使用的API。通过这种方式,App可以完全更改其实现而不会中断Interface,只要它继续提供相同的API。

要保持这些类松散耦合,您需要将clearall方法添加到App中。有了这个,Interface不需要知道App使用画布,它只需要知道App提供了一种清除绘图表面的方法,无论绘图表面是什么是

class Interface(tk.Frame):
    def __init__(self, master, app):
        ...
        self._app = app
        ...
    def clearall(self):
        self._app.clearall()


class App(object):
    def __init__(self, master):
        ...
        self._canvas = tk.Canvas(master, bg='white')
        self._interface = Interface(master, self)
        ...
    def clearall(self):
        self._calvas.delete(tk.ALL)