以动态的方式在活动窗口中修改 Trait 的视图

50 阅读3分钟

如何在活动窗口中以动态的方式修改 Trait 视图?

  • 想设置一个界面,在侦听 Trait 时,界面将在不同的预定义视图对象之间切换。
  • 如下示例所示:
class App(Handler):
    info = Instance(UIInfo)
    view_type = Enum('slider_view', 'spinner_view')
    number = Range(1, 10)
    message = Str('sawmill')

    spinner_view = View(Item('number', editor=RangeEditor(mode='spinner', high=10, low=1)), Item('message'), Item('view_type'))
    slider_view = View(Item('number', editor=RangeEditor(mode='slider', high=10, low=1)), Item('message'), Item('view_type'))

    @on_trait_change('view_type')
    def chg_view_type(self):
        self.reconstruct()

    def init_info(self, info):
        self.info = info

    def reconstruct(self):
        self.info.ui.dispose()
        self.info.object.edit_traits(view=self.view_type)
  • 使用上述代码确实可行,且适用于提供的简单示例。
  • 但实际应用程序中,编辑器很复杂(包括但不限于用于 Mayavi 场景的 SceneEditor),在处理时会销毁其所有内容。
  • 想知道有没有一种更简单的方法可以在窗口处于活动状态时以动态方式更改特定 Item 或子面板的视图,无论通过简单的方法还是技巧。

2、解决方案

  • 有一种方法可以以动态的方式更改激活窗口中 Trait 的视图,而无需销毁和重建视图对象。
  • 这种方法涉及使用 ItemEditorFactory 类,该类允许动态创建和更新 Item 编辑器。
  • 以下示例演示了如何使用 ItemEditorFactory 类来动态更改视图:
import traitsui.api
from traits.api import HasTraits, Instance, Enum, Range, Str, on_trait_change

class App(HasTraits):
    info = Instance(traitsui.api.UIInfo)
    view_type = Enum('slider_view', 'spinner_view')
    number = Range(1, 10)
    message = Str('sawmill')

    def _create_editor_factory(self):
        if self.view_type == 'slider_view':
            return traitsui.api.RangeEditor(mode='slider', high=10, low=1)
        elif self.view_type == 'spinner_view':
            return traitsui.api.RangeEditor(mode='spinner', high=10, low=1)

    editor_factory = Instance(traitsui.api.ItemEditorFactory)
    def _get_editor_factory(self):
        return self._create_editor_factory()
    def _set_editor_factory(self, value):
        self._editor_factory = value
        self._update_editor()

    @on_trait_change('view_type')
    def _update_editor(self):
        self.editor_factory = self._create_editor_factory()

    view = View(Item('number',
                     editor=editor_factory,
                     label='Number'),
                Item('message'),
                Item('view_type'))

if __name__ == "__main__":
    app = App()
    app.configure_traits()
  • 在此示例中,创建了一个 App 类,它继承自 HasTraits 类。

  • App 类具有三个属性:infoview_typenumber

  • info 属性是 traitsui.api.UIInfo 类的实例,它存储有关 Traits UI 窗口的信息。

  • view_type 属性是 Enum 类的实例,它可以是“slider_view”或“spinner_view”之一。

  • number 属性是 Range 类的实例,它可以是 1 到 10 之间的任何整数。

  • 还创建了一个 _create_editor_factory 方法,它根据 view_type 属性的值返回一个 ItemEditorFactory 类的实例。

  • editor_factory 属性是 ItemEditorFactory 类的实例,它用于创建和更新 number 属性的编辑器。

  • _get_editor_factory_set_editor_factory 方法是 editor_factory 属性的访问器和修改器。

  • _update_editor 方法用于在更改 view_type 属性的值时更新 number 属性的编辑器。

  • 最后,创建了一个 View 对象,它定义了 Traits UI 窗口的布局。

  • if __name__ == "__main__": 块中,创建了一个 App 类的实例并调用其 configure_traits() 方法来显示 Traits UI 窗口。

  • 当用户更改 view_type 属性的值时,_update_editor 方法将被调用,该方法将创建一个新的 ItemEditorFactory 实例并将其分配给 editor_factory 属性。

  • 这将导致 number 属性的编辑器被更新,该编辑器将根据 view_type 属性的值而有所不同。