我使用traitsui.api.Handler
来捕捉和处理traitsui.api.View
的事件,该视图包含一个按钮,其行为是从包含多个图的容器中删除一个图。使用remove
按钮,调用pop()
方法并删除绘图时,将访问容器的组件列表。但是,视图不会重绘,因此绘图似乎保持不变。通过拖动角落来调整窗口大小将强制重绘,确认pop()
问题是:如何以编程方式强制重绘?
在我看来,这样做的正确位置将在Handler的setattr
方法中,就在pop()
之后的情节。
# Major library imports
from numpy import linspace
from scipy.special import jn
# Enthought library imports
from enable.api import Container, ComponentEditor
from traits.api import HasTraits, Instance, Button, Int, Str
from traitsui.api import Item, HGroup, View, VSplit, UItem, InstanceEditor, Handler
# Chaco imports
from chaco.api import ArrayPlotData, GridContainer, Plot
# ===============================================================================
# Attributes to use for the plot view.
size = (1000, 800)
COLOR_PALETTE = [
(0.65098039, 0.80784314, 0.89019608, 1.0),
(0.12156863, 0.47058824, 0.70588235, 1.0),
(0.69803922, 0.8745098, 0.54117647, 1.0),
(0.2, 0.62745098, 0.17254902, 1.0),
(0.98431373, 0.60392157, 0.6, 1.0),
(0.89019608, 0.10196078, 0.10980392, 1.0),
(0.99215686, 0.74901961, 0.43529412, 1.0),
(1., 0.49803922, 0., 1.0),
(0.79215686, 0.69803922, 0.83921569, 1.0),
]
class InstanceUItem(UItem):
"""Convenience class for including an Instance in a View"""
style = Str('custom')
editor = Instance(InstanceEditor, ())
# ===============================================================================
# # ManagerHandler will be the View's handler
#===============================================================================
class ManagerHandler(Handler):
def setattr(self, info, object, name, value):
Handler.setattr(self, info, object, name, value)
info.ui.context['pgrid'].plots_container.components.pop()
#At this point, the container does not redraw, and so, while it no longer
#contains the last plot in its components collection, that plot is still
# visible
# ===============================================================================
# # PlotsGrid class that is used by the demo
#===============================================================================
class PlotsGrid(HasTraits):
plots_container = Instance(Container)
rows = Int(3)
cols = Int(3)
#===============================================================================
# # Create the plots, this is adapted from the chaco GridContainer demo
#===============================================================================
def _plots_container_default(self):
# Create a GridContainer to hold all of our plots
container = GridContainer(padding=20, fill_padding=True,
bgcolor="lightgray", use_backbuffer=True,
shape=(self.rows, self.cols), spacing=(20, 20))
# Create the initial series of data
x = linspace(-5, 15.0, 100)
pd = ArrayPlotData(index=x)
# Plot some bessel functions and add the plots to our container
for i in range(self.rows * self.cols):
pd.set_data("y" + str(i), jn(i, x))
plot = Plot(pd)
plot.plot(("index", "y" + str(i)),
color=tuple(COLOR_PALETTE[i]), line_width=2.0,
bgcolor="white", border_visible=True)
container.add(plot)
return container
# ===============================================================================
# # Controls HasTraits provides a button used to wire in the desired behavior
#===============================================================================
class Controls(HasTraits):
rem_plot = Button("remove ...")
def _rem_plot_changed(self):
print "rem plot changed"
# ===============================================================================
# # manager_view provides the View and defines its layout
#===============================================================================
manager_view = View(
VSplit(
HGroup(
Item('controls.rem_plot', height=32)
),
Item('pgrid.plots_container', editor=ComponentEditor(size=size), show_label=False),
show_border=True
),
handler=ManagerHandler(),
resizable=True
)
grid = PlotsGrid()
ctrl = Controls()
if __name__ == "__main__":
ctrl.configure_traits(view=manager_view, context={'pgrid': grid, 'controls': ctrl})
答案 0 :(得分:3)
实现此功能的最简单方法是在弹出绘图后在绘图容器上调用invalidate_and_redraw
。在这种情况下,您可以将对pop
的调用修改为:
plots_container = info.ui.context['pgrid'].plots_container
plots_container.components.pop()
plots_container.invalidate_and_redraw()
更长时间的讨论:
理想情况下,这将由Chaco处理。部分问题是容器未设计为直接修改components
列表。相反,(我猜)其意图是让用户在plots_container.remove
列表中的某个项目上调用components
。
那就是说, 似乎也不起作用。事实证明remove
使当前状态无效,但不请求重绘。 (我的猜测是chaco / enable不会自动重绘,因为连续可能存在许多缓存失效操作;例如,如果要从此容器中删除所有绘图,则只需要在所有调用之后重绘remove
,而不是每一个之后。)
因此,要实际使用这种替代方法,您可以编写如下内容:
plot = plots_container.components[-1]
plots_container.remove(plot)
plots_container.request_redraw()