5.14. 使用 NormalTUISpoke 来定义文本接口 Spoke
重新定义简单 TUI Spoke 示例演示了一种实现 TUI spoke 的方法,其中它的方法处理打印和处理可用的和提供的数据。但是,有不同的方法来使用 pyanaconda.ui.tui.spokes
软件包中的 NormalTUISpoke
类实现此目的。通过继承此类,您只需指定应在其中设置的字段和属性,就可实现典型的 TUI spoke 。以下示例演示了这一点:
先决条件
-
您已在
TUI
目录下添加了一组新的子软件包,如 Anaconda 附加组件结构中所述。
步骤
- 根据以下示例,创建带有所有必要定义的模块,来对 Add-on 文本用户界面(TUI)添加支持。
例 5.12. 使用 NormalTUISpoke 来定义文本接口 Spoke
class HelloWorldEditSpoke(NormalTUISpoke): """Example class demonstrating usage of editing in TUI""" category = HelloWorldCategory def init(self, data, storage, payload): """ :see: simpleline.render.screen.UIScreen :param data: data object passed to every spoke to load/store data from/to it :type data: pykickstart.base.BaseHandler :param storage: object storing storage-related information (disks, partitioning, boot loader, etc.) :type storage: blivet.Blivet :param payload: object storing packaging-related information :type payload: pyanaconda.packaging.Payload """ super().init(self, *args, **Kwargs) self.title = N_("Hello World Edit") self._container = None # values for user to set self._checked = False self._unconditional_input = "" self._conditional_input = "" def refresh(self, args=None): """ The refresh method that is called every time the spoke is displayed. It should update the UI elements according to the contents of self.data. :see: pyanaconda.ui.common.UIObject.refresh :see: simpleline.render.screen.UIScreen.refresh :param args: optional argument that may be used when the screen is scheduled :type args: anything """ super().refresh(args) self._container = ListColumnContainer(columns=1) # add ListColumnContainer to window (main window container) # this will automatically add numbering and will call callbacks when required self.window.add(self._container) self._container.add(CheckboxWidget(title="Simple checkbox", completed=self._checked), callback=self._checkbox_called) self._container.add(EntryWidget(title="Unconditional text input", value=self._unconditional_input), callback=self._get_unconditional_input) # show conditional input only if the checkbox is checked if self._checked: self._container.add(EntryWidget(title="Conditional password input", value="Password set" if self._conditional_input else ""), callback=self._get_conditional_input) self.window.add_with_separator(self._container) def _checkbox_called(self, data): # pylint: disable=unused-argument """Callback when user wants to switch checkbox. :param data: can be passed when adding callback in container (not used here) :type data: anything """ self._checked = not self._checked def _get_unconditional_input(self, data): # pylint: disable=unused-argument """Callback when the user wants to set unconditional input. :param data: can be passed when adding callback in container (not used here) :type data: anything """ dialog = Dialog( "Unconditional input", conditions=[self._check_user_input] ) self._unconditional_input = dialog.run() def _get_conditional_input(self, data): # pylint: disable=unused-argument """Callback when the user wants to set conditional input. :param data: can be passed when adding callback in container (not used here) :type data: anything """ dialog = PasswordDialog( "Unconditional password input", policy_name=PASSWORD_POLICY_ROOT ) self._conditional_input = dialog.run() def _check_user_input(self, user_input, report_func): """Check if the user has written a valid value. :param user_input: user input for validation :type user_input: str :param report_func: function for reporting errors on user input :type report_func: func with one param """ if re.match(r'^\w+$', user_input): return True else: report_func("You must set at least one word") return False def input(self, args, key): """ The input method that is called by the main loop on user's input. :param args: optional argument that may be used when the screen is scheduled :type args: anything :param key: user's input :type key: unicode :return: if the input should not be handled here, return it, otherwise return InputState.PROCESSED or InputState.DISCARDED if the input was processed successfully or not respectively :rtype: enum InputState """ if self._container.process_user_input(key): return InputState.PROCESSED_AND_REDRAW else: return super().input(args, key) @property def completed(self): # completed if user entered something non-empty to the Conditioned input return bool(self._conditional_input) @property def status(self): return "Hidden input %s" % ("entered" if self._conditional_input else "not entered") def apply(self): # nothing needed here, values are set in the self.args tree pass