更改某些属性后如何强制重绘小部件?

Posted

技术标签:

【中文标题】更改某些属性后如何强制重绘小部件?【英文标题】:How to force redraw of a widget after changing some of its attributes? 【发布时间】:2017-09-10 14:13:42 【问题描述】:

在与matplotlib.widgets.Slider 实例关联的回调中,我想修改Slider valminvalmaxval 属性,然后重新绘制Slider。当我尝试重新绘制它时,什么也没有发生。

在回调完成之前,我调用了plt.draw(),并且在情节的其余部分正确更新时,Slider 看起来和以前一样。我还尝试在SliderAxes 上调用draw(),同样没有明显变化。

如何在更改属性后强制重新绘制 Slider 实例?

谢谢!

更新

这是一个演示问题的小程序(带有粗略的对话框)。想要的行为是,通过单击单选按钮的不同值,滑块会更改值范围、当前值和标签。相反,当点击“渐变”时,滑块停止响应(不能再拖动),当点击“渐变”或“通道”时,尽管调用了plt.draw()

from matplotlib import pyplot as plt
from matplotlib import gridspec
from matplotlib.widgets import Slider, RadioButtons

# Set the grid
grid = gridspec.GridSpec(2, 1, height_ratios=[1, 2])

# Plot the sliders
axes_slider = plt.subplot(grid[0, 0])
slider = Slider(axes_slider, 'Channel', valmin=0, valmax=255, valinit=128)

# Plot the radio buttons
axes_button = plt.subplot(grid[1, 0])
button = RadioButtons(axes_button, ('Gradient', 'Channel'), active=1)

plt.tight_layout(h_pad=0)
plt.subplots_adjust(left=.2, right=.9)

def update(_):
    take_gradient = True if button.value_selected == 'Gradient' else False
    if take_gradient:
        slider.valmin = -1
        slider.valmax = 1
        slider.val = 0
        slider.label= 'Gradient'
        slider.valinit = 0
    else:
        slider.valmin = 0
        slider.valmax = 255
        slider.val = 128
        slider.label = 'Channel'
        slider.valinit = 128
    plt.draw()

# Register call-backs with widgets
slider.on_changed(update)
button.on_clicked(update)

plt.show()

【问题讨论】:

我会尝试编写一个仍然可以重现问题的简短程序。 我已经用代码示例更新了这个问题。 【参考方案1】:

滑块本身是一个承载和管理一些参数的类。它没有draw方法。

也就是说,仅设置滑块的参数是不够的,您还需要更新滑块所在的轴。最后,这一切都归结为执行滑块正在执行初始化的步骤,所以你可以简单地调用silder的__init__函数。

我强烈建议使用两种不同的功能,一种用于更改在单击按钮时调用的滑块,另一种用于调整滑块值时应该发生的事情。

这是一个工作示例:

from matplotlib import pyplot as plt
from matplotlib import gridspec
from matplotlib.widgets import Slider, RadioButtons

# Set the grid
grid = gridspec.GridSpec(2, 1, height_ratios=[1, 2])

# Plot the sliders
axes_slider = plt.subplot(grid[0, 0])
slider = Slider(axes_slider, 'Channel', valmin=0, valmax=255, valinit=128)

# Plot the radio buttons
axes_button = plt.subplot(grid[1, 0])
button = RadioButtons(axes_button, ('Gradient', 'Channel'), active=1)

plt.tight_layout(h_pad=0)
plt.subplots_adjust(left=.2, right=.9)

def buttonupdate(val):
    if val == "Gradient":
        axes_slider.clear()
        slider.__init__(axes_slider, 'Gradient', valmin=-1, valmax=1, valinit=0)        
    else:
        axes_slider.clear()
        slider.__init__(axes_slider, 'Channel', valmin=0, valmax=255, valinit=128) 
    plt.gcf().canvas.draw_idle()

def sliderupdate(val):
    if slider.label.get_text() == 'Gradient':
        #do something depending on gradient value
        pass
    else:
        #do something depending on channel value
        pass

# Register call-backs with widgets
slider.on_changed(sliderupdate)
button.on_clicked(buttonupdate)

plt.show()

【讨论】:

以上是关于更改某些属性后如何强制重绘小部件?的主要内容,如果未能解决你的问题,请参考以下文章

使用SDL开发IMGUI

使用 QPainter 的动画文本

用于 Qt 4、Python 3 的 matplotlib 小部件

如何更改 GTK 容器小部件的大小?

在 pyqtgraph 中绘制大数组

如何更改按钮单击 GTK c 上的多个小部件属性