我可以强制我的启用容器从traitsui Handler重绘吗?

时间:2014-12-05 19:03:44

标签: python enthought traitsui chaco

我使用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})

1 个答案:

答案 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()