5.13. 定义一个简单的 TUI Spoke

以下示例演示了在 Hello World 示例附加组件中一个简单的文本用户界面(TUI) spoke 的实现:

先决条件

流程

  • 根据以下示例,创建带有所有必要定义的模块来添加对附加文本用户界面(TUI)的支持:

例 5.11. 定义一个简单的 TUI Spoke

def __init__(self, *args, **kwargs):
    """
    Create the representation of the spoke.

    :see: simpleline.render.screen.UIScreen
    """
    super().__init__(*args, **kwargs)
    self.title = N_("Hello World")
    self._hello_world_module = HELLO_WORLD.get_proxy()
    self._container = None
    self._reverse = False
    self._lines = ""

def initialize(self):
    """
    The initialize method that is called after the instance is created.
    The difference between __init__ and this method is that this may take
    a long time and thus could be called in a separated thread.

    :see: pyanaconda.ui.common.UIObject.initialize
    """
    # nothing to do here
    super().initialize()

def setup(self, args=None):
    """
    The setup method that is called right before the spoke is entered.
    It should update its state according to the contents of DBus modules.

    :see: simpleline.render.screen.UIScreen.setup
    """
    super().setup(args)

    self._reverse = self._hello_world_module.Reverse
    self._lines = self._hello_world_module.Lines

    return True

def refresh(self, args=None):
    """
    The refresh method that is called every time the spoke is displayed.
    It should generate the UI elements according to its state.

    :see: pyanaconda.ui.common.UIObject.refresh
    :see: simpleline.render.screen.UIScreen.refresh
    """
    super().refresh(args)

    self._container = ListColumnContainer(
        columns=1
    )
    self._container.add(
        CheckboxWidget(
            title="Reverse",
            completed=self._reverse
        ),
        callback=self._change_reverse
    )
    self._container.add(
        EntryWidget(
            title="Hello world text",
            value="".join(self._lines)
        ),
        callback=self._change_lines
    )

    self.window.add_with_separator(self._container)

def _change_reverse(self, data):
    """
    Callback when user wants to switch checkbox.
    Flip state of the "reverse" parameter which is boolean.
    """
    self._reverse = not self._reverse

def _change_lines(self, data):
    """
    Callback when user wants to input new lines.
    Show a dialog and save the provided lines.
    """
    dialog = Dialog("Lines")
    result = dialog.run()
    self._lines = result.splitlines(True)

def input(self, args, key):
    """
    The input method that is called by the main loop on user's input.

    * If the input should not be handled here, return it.
    * If the input is invalid, return InputState.DISCARDED.
    * If the input is handled and the current screen should be refreshed,
      return InputState.PROCESSED_AND_REDRAW.
    * If the input is handled and the current screen should be closed,
      return InputState.PROCESSED_AND_CLOSE.

    :see: simpleline.render.screen.UIScreen.input
    """
    if self._container.process_user_input(key):
        return InputState.PROCESSED_AND_REDRAW

    if key.lower() == Prompt.CONTINUE:
        self.apply()
        self.execute()
        return InputState.PROCESSED_AND_CLOSE

    return super().input(args, key)

def apply(self):
    """
    The apply method is not called automatically for TUI. It should be called
    in input() if required. It should update the contents of internal data
    structures with values set in the spoke.
    """
    self._hello_world_module.SetReverse(self._reverse)
    self._hello_world_module.SetLines(self._lines)

def execute(self):
    """
    The execute method is not called automatically for TUI. It should be called
    in input() if required. It is supposed to do all changes to the runtime
    environment according to the values set in the spoke.
    """
    # nothing to do here
    pass
注意

如果仅调用祖先的 init,则不需要覆盖 init 方法,但示例中的注释描述了以可理解的方式传递给 spoke 类构造器的参数。

在上例中:

  • setup 方法为每个条目上的 spoke 的内部属性设置默认值,然后由 refresh 方法显示,通过 input 方法更新并使用 apply 方法来更新内部数据结构。
  • execute 方法与 GUI 中的等效方法具有相同的目的;在这种情况下,该方法没有任何效果。
  • input 方法特定于文本界面;在 Kickstart 或 GUI 中没有等效的方法。input 方法负责用户交互。
  • input 方法处理输入的字符串,并根据其类型和值采取措施。上例要求输入任何值,然后将它存储为内部属性(密钥)。在更复杂的附加组件中,您通常需要执行一些不平凡的操作,如将字母解析为操作、将数字转换为整数、显示额外的屏幕或切换布尔值。
  • 输入类的 返回 值必须是 InputState 枚举或 input 字符串本身,如果此 input 应该由不同的屏幕处理。与图形模式不同,applyexecute 方法不会在保留 spoke 时自动调用;它们必须从输入法显式调用。同样适用于关闭(隐藏) spoke 屏幕:必须从 close 方法显式调用它。

若要显示另一个屏幕,例如,您需要在不同的 spoke 中输入的附加信息,您可以实例化另一个 TUIObject ,并使用 ScreenHandler.push_screen_modal() 来显示它。

由于基于文本的界面的限制,TUI spoke 往往具有非常相似的结构,由用户应选中或取消选中并填充的复选框或条目列表组成。