首页 > 解决方案 > 有一个 matplotlib 按钮断开它自己的回调

问题描述

我想要一个只能使用一次的 matplotlib 按钮。理想情况下,我可以通过断开回调来做到这一点。但是,回调断开本身存在时间问题。

import matplotlib.pyplot as plt
from matplotlib.widgets import Button

fig, ax = plt.subplots()
donebutton = Button(ax, "Disconnect the button")
def donecallback(event):
    donebutton.disconnect(donecid)
    print("Disconnected")

donecid = donebutton.on_clicked(donecallback)

plt.show()

要断开回调,我需要它的回调 ID ,donecid这是我在连接回调时获得的。要连接回调,我首先必须定义它,donecallback. 要定义回调,我必须已经知道 CID。因此,我陷入了先有鸡还是先有蛋的问题。

有一些变通方法,例如定义一个类以便我可以通过 将数据传递到回调self中,有一个全局标志来跟踪按钮是否被按下,或者创建一个新的、相同的按钮而不连接回调。但是,如果有更简单的方法,那就太好了。有没有?

编辑:当我使用我给出的代码时会发生以下错误。或dnalow提供的代码。

    func(*args, **kwargs)
  File "C:\Users\MyName\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.8_qbz5n2kfra8p0\LocalCache\local-packages\Python38\site-packages\matplotlib\widgets.py", line 210, in _release
    for cid, func in self.observers.items():
RuntimeError: dictionary changed size during iteration```

标签: pythonmatplotlibcallback

解决方案


您可以围绕它包装一个类:



class MyButton(Button):
    def on_clicked(self, func):
        self.cb_id = super(MyButton, self).on_clicked(func)
        return self.cb_id

    def disconnect(self):
        return super(MyButton, self).disconnect(self.cb_id)



donebutton = MyButton(ax, "Disconnect the button")
def donecallback(event):
    donebutton.disconnect()
    print("Disconnected")

donebutton.on_clicked(donecallback)

但是,人们可能希望更好地处理定义多个事件的情况。此外,您更愿意定义一个在第一个事件后自动断开连接的 Button 类?!

编辑:

上述方法不起作用。相反,您可以使用该active属性来停用整个按钮。它不会与某个回调函数断开连接,因此它并不是您真正要求的。

按照你的例子:

import matplotlib.pyplot as plt
from matplotlib.widgets import Button

fig, ax = plt.subplots()
donebutton = Button(ax, "Disconnect the button")
def donecallback(event):
    donebutton.active = False
    print("Disconnected")

donecid = donebutton.on_clicked(donecallback)

plt.show()

编辑2:

_release通过覆盖按钮的方法的另一种方法:

class SingleUseButton(Button):
    def _release(self, event):
        if self.ignore(event):
            return
        if event.canvas.mouse_grabber != self.ax:
            return
        event.canvas.release_mouse(self.ax)
        if not self.eventson:
            return
        if event.inaxes != self.ax:
            return
        for cid in list(self.observers):
            func = self.observers.pop(cid)
            func(event)


推荐阅读