5.13. Defining a Simple TUI Spoke


The following example shows the implementation of a simple Text User Interface (TUI) spoke in the Hello World sample add-on:

Prerequisites

Procedure

  • Create modules with all required definitions to add support for the add-on text user interface (TUI), according to the following examples:

    class HelloWorldSpoke(NormalTUISpoke):
        # category this spoke belongs to
        category = HelloWorldCategory
    
    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

    For more details and latest code, see the Hello World Anaconda Addon - GitHub Repository.

    참고

    It is not necessary to override the init method if it only calls the ancestor’s init, but the comments in the example describe the arguments passed to constructors of spoke classes in an understandable way.

    In the previous example:

  • The setup method sets up a default value for the internal attribute of the spoke on every entry, which is then displayed by the refresh method, updated by the input method and used by the apply method to update internal data structures.
  • The execute method has the same purpose as the equivalent method in the GUI; in this case, the method has no effect.
  • The input method is specific to the text interface; there are no equivalents in Kickstart or GUI. The input methods are responsible for user interaction.
  • The input method processes the entered string and takes action depending on its type and value. The above example asks for any value and then stores it as an internal attribute (key). In more complex add-ons, you typically need to perform some non-trivial actions, such as parse letters as actions, convert numbers into integers, show additional screens or toggle boolean values.
  • The return value of the input class must be either the InputState enum or the input string itself, in case this input should be processed by a different screen. In contrast to the graphical mode, the apply and execute methods are not called automatically when leaving the spoke; they must be called explicitly from the input method. The same applies to closing (hiding) the spoke’s screen: it must be called explicitly from the close method.

    To show another screen, for example if you need additional information that was entered in a different spoke, you can instantiate another TUIObject and use ScreenHandler.push_screen_modal() to show it.

    Due to restrictions of the text-based interface, TUI spokes tend to have a very similar structure, that consists of a list of checkboxes or entries that should be checked or unchecked and populated by the user.

Red Hat logoGithubredditYoutubeTwitter

자세한 정보

평가판, 구매 및 판매

커뮤니티

Red Hat 문서 정보

Red Hat을 사용하는 고객은 신뢰할 수 있는 콘텐츠가 포함된 제품과 서비스를 통해 혁신하고 목표를 달성할 수 있습니다. 최신 업데이트를 확인하세요.

보다 포괄적 수용을 위한 오픈 소스 용어 교체

Red Hat은 코드, 문서, 웹 속성에서 문제가 있는 언어를 교체하기 위해 최선을 다하고 있습니다. 자세한 내용은 다음을 참조하세요.Red Hat 블로그.

Red Hat 소개

Red Hat은 기업이 핵심 데이터 센터에서 네트워크 에지에 이르기까지 플랫폼과 환경 전반에서 더 쉽게 작업할 수 있도록 강화된 솔루션을 제공합니다.

Theme

© 2026 Red Hat
맨 위로 이동