5.10. アドオンのグラフィカルユーザーインターフェイス (GUI) サポートの追加
NormalSpoke クラスを継承したクラスを定義することで、アドオンのグラフィカルユーザーインターフェイス (GUI) のサポートを追加できます。
-
Normalspokeクラスに必要な属性を定義する -
initメソッドとinitializeメソッドを定義します。 -
refresh、apply、およびexecuteメソッドを定義します。 -
statusおよびready、completedおよびmandatoryのプロパティーを定義します。
前提条件
- アドオンにキックスタートのサポートが含まれている。Anaconda アドオンの構造 を参照してください。
-
Anaconda固有の Gtk ウィジェット (SpokeWindowなど) が含まれるanaconda-widgetsおよびanaconda-widgets-develパッケージがインストールされている。
手順
アドオンのグラフィカルユーザーインターフェイス (GUI) のサポートを追加するには、次の例に従って、必要なすべての定義を含む次のモジュールを作成します。
# will never be translated _ = lambda x: x N_ = lambda x: x # the path to addons is in sys.path so we can import things from org_fedora_hello_world from org_fedora_hello_world.gui.categories.hello_world import HelloWorldCategory from pyanaconda.ui.gui.spokes import NormalSpoke # export only the spoke, no helper functions, classes or constants all = ["HelloWorldSpoke"] class HelloWorldSpoke(FirstbootSpokeMixIn, NormalSpoke): """ Class for the Hello world spoke. This spoke will be in the Hello world category and thus on the Summary hub. It is a very simple example of a unit for the Anaconda's graphical user interface. Since it is also inherited form the FirstbootSpokeMixIn, it will also appear in the Initial Setup (successor of the Firstboot tool). :see: pyanaconda.ui.common.UIObject :see: pyanaconda.ui.common.Spoke :see: pyanaconda.ui.gui.GUIObject :see: pyanaconda.ui.common.FirstbootSpokeMixIn :see: pyanaconda.ui.gui.spokes.NormalSpoke """ # class attributes defined by API # # list all top-level objects from the .glade file that should be exposed # to the spoke or leave empty to extract everything builderObjects = ["helloWorldSpokeWindow", "buttonImage"] # the name of the main window widget mainWidgetName = "helloWorldSpokeWindow" # name of the .glade file in the same directory as this source uiFile = "hello_world.glade" # category this spoke belongs to category = HelloWorldCategory # spoke icon (will be displayed on the hub) # preferred are the -symbolic icons as these are used in Anaconda's spokes icon = "face-cool-symbolic" # title of the spoke (will be displayed on the hub) title = N_("_HELLO WORLD")__all__属性はspokeクラスをエクスポートします。この後に、以前 GUI アドオンの基本機能 で言及した、属性の定義を含む定義の最初の行が続きます。これらの属性値は、com_example_hello_world/gui/spokes/hello.gladeファイルで定義されるウィジェットを参照します。この他に、以下の 2 つの重要な属性があります。-
category。この値は、com_example_hello_world.gui.categoriesモジュールのHelloWorldCategoryクラスからインポートされます。アドオンへのパスがsys.pathにあるHelloWorldCategory。これにより、com_example_hello_worldパッケージから値をインポートできます。category属性はN_ function名の一部で、変換用の文字列をマークしますが、変換は後の段階で行われるため、変換されていない文字列のバージョンを返します。 title。この属性の定義にはアンダースコアが 1 つ含まれています。title属性アンダースコアは、タイトル自体の先頭をマークし、Alt+Hキーボードショートカットを使用してスポークに到達できるようにします。通常、クラス定義のヘッダーとクラス
attributesの定義に続くのは、クラスのインスタンスを初期化するコンストラクターです。Anaconda グラフィカルインターフェイスオブジェクトの場合、新しいインスタンスの初期化には__init__メソッドおよびinitializeメソッドの 2 つのメソッドがあります。このようなメソッドが 2 つある理由は、
spokeの初期化に時間がかかる可能性があるため、あるタイミングで GUI オブジェクトがメモリーに作成され、別のタイミングで完全に初期化される可能性があるためです。したがって、__init__メソッドは親の__init__メソッドのみを呼び出し、たとえば、GUI 以外の属性を初期化する必要があります。一方、インストーラーのグラフィカルユーザーインターフェイスの初期化時に呼び出されるinitializeメソッドは、スポークの完全な初期化を完了する必要があります。Hello World add-onの例で、以下のようにこの 2 つのメソッドを定義します。__init__メソッドに渡される引数の数および説明をメモしてください。以下に例を示します。def __init__(self, data, storage, payload): """ :see: pyanaconda.ui.common.Spoke.init :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 """ NormalSpoke.init(self, data, storage, payload) self._hello_world_module = HELLO_WORLD.get_proxy() 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 separate thread. :see: pyanaconda.ui.common.UIObject.initialize """ NormalSpoke.initialize(self) self._entry = self.builder.get_object("textLines") self._reverse = self.builder.get_object("reverseCheckButton")__init__メソッドに渡されるデータパラメーターは、すべてのデータが保存されるキックスタートファイルのメモリー内ツリーのような表示になります。ancestor の__init__メソッドのいずれかで、self.data属性に格納されます。これにより、クラス内の他のすべてのメソッドで構造の読み取りおよび修正が可能になります。注記RHEL10 以降、
storage objectは利用できなくなりました。アドオンがストレージ設定と対話する必要がある場合は、Storage DBusモジュールを使用します。HelloWorldData クラスは Hello World アドオンの例 ですでに定義されているため、このアドオンの self.data にはすでにサブツリーがあります。クラスのインスタンスである root は
self.data.addons.com_example_hello_worldとして利用できます。ancestor の
__init__が実行するもう 1 つのアクションは、スポークの.gladeファイルを使用して GtkBuilder のインスタンスを初期化し、それをself.builderとして保存することです。initializeメソッドは GtkBuilder を使用して、キックスタートファイルの %addon セクションにあるテキストを表示および変更するために使用されるGtkTextEntryを取得します。__init__およびinitializeメソッドは両方とも、スポークの作成時に重要となります。しかし、スポークの主なロールは、ユーザーがアクセスして、スポークが表示および設定する値を変更または確認することです。これを有効にするには、その他の 3 つの方法を使用できます。-
refresh: スポークがアクセスされようとするときに呼び出されます。このメソッドは、スポーク (主に UI 要素) の状態を更新し、表示されるデータが内部データ構造と一致するようにします。これにより、self.data 構造に保存されている現在の値が表示されるようにします。 -
apply: スポークが残っている場合に呼び出され、UI 要素の値をself.data構造に戻す際に使用されます。 execute: ユーザーがスポークを離れる場合に呼び出され、スポークの新しい状態に基づいてランタイムの変更を実行する際に使用されます。これらの関数は、以下のように Hello World アドオンのサンプルに実装されます。
def refresh(self): """ The refresh method that is called every time the spoke is displayed. It should update the UI elements according to the contents of internal data structures. :see: pyanaconda.ui.common.UIObject.refresh """ lines = self._hello_world_module.Lines self._entry.get_buffer().set_text("".join(lines)) reverse = self._hello_world_module.Reverse self._reverse.set_active(reverse) def apply(self): """ The apply method that is called when user leaves the spoke. It should update the D-Bus service with values set in the GUI elements. """ buf = self._entry.get_buffer() text = buf.get_text(buf.get_start_iter(), buf.get_end_iter(), True) lines = text.splitlines(True) self._hello_world_module.SetLines(lines) self._hello_world_module.SetReverse(self._reverse.get_active()) def execute(self): """ The execute method that is called when the spoke is exited. It is supposed to do all changes to the runtime environment according to the values set in the GUI elements. """ # nothing to do here pass複数の追加のメソッドを使用して、スポークの状態を制御できます。
-
ready: スポークへアクセスできるかどうかを判断します。値が "False" の場合はspokeへアクセスできません。たとえば、パッケージソースを設定する前にPackage Selectionスポークにアクセスできません。 -
completed- スポークが完了しているかどうかを確認します。 mandatory: スポークが必須かどうかを判別します。たとえば、自動パーティションを使用する場合でも、常にアクセスする必要があるInstallation Destinationスポークが必須かどうか判別します。これらの属性はすべて、インストールプロセスの現在の状態に基づいて動的に決定する必要があります。以下は、Hello World アドオンにおけるこれらのメソッドの実装例です。この実装では、
HelloWorldDataクラスの text 属性に特定の値を設定する必要があります。@property def ready(self): """ The ready property reports whether the spoke is ready, that is, can be visited or not. The spoke is made (in)sensitive based on the returned value of the ready property. :rtype: bool """ # this spoke is always ready return True @property def mandatory(self): """ The mandatory property that tells whether the spoke is mandatory to be completed to continue in the installation process. :rtype: bool """ # this is an optional spoke that is not mandatory to be completed return Falseこれらのプロパティーが定義された後、スポークはそのアクセス可能性と完全性を制御できますが、内部で設定された値のサマリーを提供することはできません。スポークにアクセスして、スポークがどのように設定されているかを確認する必要がありますが、これは望ましくない場合があります。このため、
statusという追加のプロパティーが存在します。このプロパティーには、設定された値の短いサマリーを含む 1 行のテキストが含まれ、スポークタイトルの下のハブに表示することができます。status プロパティーは、以下のように
Hello Worldの例のアドオンで定義されます。@property def status(self): """ The status property that is a brief string describing the state of the spoke. It should describe whether all values are set and if possible also the values themselves. The returned value will appear on the hub beneath the spoke's title. :rtype: str """ lines = self._hello_world_module.Lines if not lines: return _("No text added") elif self._hello_world_module.Reverse: return _("Text set with {} lines to reverse").format(len(lines)) else: return _("Text set with {} lines").format(len(lines))例で説明しているプロパティーをすべて定義した後に、アドオンには、グラフィカルユーザーインターフェイス (GUI) とキックスタートを示す完全なサポートがあります。
注記ここで示した例は非常にシンプルで、制御を含むものはありません。GUI で機能的かつインタラクティブなスポークを開発するには、Python Gtk プログラミングに関する知識が必要です。
主な制限の 1 つとして、それぞれのスポークに独自のメインウィンドウ (
SpokeWindowウィジェットのインスタンス) が必要である点が挙げられます。このウィジェットは、Anaconda 固有の他のウィジェットとともに、anaconda-widgetsパッケージにあります。Gladeなど、GUI サポートでアドオンの開発に必要な他のファイルは、anaconda-widgets-develパッケージで見つけることができます。グラフィカルインターフェイスのサポートモジュールに必要なメソッドをすべて含めたら、次のセクションに進み、テキストベースのユーザーインターフェイスのサポートを追加できます。