5.10. アドオングラフィカルユーザーインターフェイス (GUI) のサポートの追加
本セクションでは、以下の大まかな手順を実行することで、アドオンのグラフィカルユーザーインターフェイス (GUI) にサポートを追加する方法を説明します。
- Normalspoke クラスに必要な属性を定義します。
-
__init__
とinitialize
メソッドを定義します。 -
refresh
、apply
、およびexecute
メソッドを定義します。 -
status
およびready
、completed
およびmandatory
のプロパティーを定義します。
前提条件
- アドオンには、キックスタートのサポートが含まれています。Anaconda アドオンの構造 を参照してください。
-
Anaconda
固有の Gtk ウィジェット (SpokeWindow
など) が含まれる anaconda-widgets および anaconda-widgets-devel パッケージをインストールします。
手順
- 以下の例に従って、アドオングラフィカルユーザーインターフェイス (GUI) のサポートを追加するために必要なすべての定義で以下のモジュールを作成します。
例5.4 Normalspoke クラスに必要な属性の定義
# 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
名の一部で、変換用の文字列をマークしますが、変換は後の段階で行われるため、変換されていない文字列のバージョンを返します。 -
タイトル
。定義内にアンダースコアが 1 つ含まれています。title
属性アンダースコアは、タイトル自体の先頭をマークし、Alt+H
キーボードショートカットを使用してスポークに到達できるようにします。
通常、クラス定義のヘッダーとクラス attributes
の定義に続くのは、クラスのインスタンスを初期化するコンストラクターです。Anaconda グラフィカルインターフェイスオブジェクトの場合、新しいインスタンスの初期化には __init__
メソッドおよび initialize
メソッドの 2 つのメソッドがあります。
このようなメソッドが 2 つある理由は、spoke
の初期化に時間がかかる可能性があるため、あるタイミングで GUI オブジェクトがメモリーに作成され、別のタイミングで完全に初期化される可能性があるためです。したがって、__init__
メソッドは親の _init__
メソッドのみを呼び出し、たとえば、GUI 以外の属性を初期化する必要があります。一方、インストーラーのグラフィカルユーザーインターフェイスの初期化時に呼び出される initialize
メソッドは、スポークの完全な初期化を完了する必要があります。
Hello World add-on
の例で、以下のようにこの 2 つのメソッドを定義します。__init__
メソッドに渡される引数の数および説明をメモしてください。
例5.5 __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, bootloader, 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
属性に格納されます。これにより、クラス内の他のすべてのメソッドで構造の読み取りおよび修正が可能になります。
storage object
は RHEL8 以降利用できなくなりました。アドオンがストレージ設定と対話する必要がある場合は、Storage DBus
モジュールを使用します。
HelloWorldData クラスは Hello World アドオンの例 ですでに定義されているため、このアドオンの self.data にはすでにサブツリーがあります。クラスのインスタンスである root は self.data.addons.com_example_hello_world
として利用できます。
ancestor の __init__
が実行するもう 1 つのアクションは、spoke's .glade
で GtkBuilder のインスタンスを初期化し、これを self.builder
として保存することです。initialize
メソッドはこれを使用して、キックスタートファイルの %addon セクションにあるテキストを表示し、変更するために使用される GtkTextEntry
を取得します。
__init__
および initialize
メソッドは両方とも、スポークの作成時に重要となります。ただし、スポークの主なロールは、スポークの値の表示と設定を変更または確認したいユーザーがアクセスすることです。これを有効にするには、その他の 3 つの方法を使用できます。
-
refresh
: スポークがアクセスされようとするときに呼び出されます。このメソッドは、スポーク (主に UI 要素) の状態を更新し、表示されるデータが内部データ構造と一致するようにします。これにより、self.data 構造に保存されている現在の値が表示されるようにします。 -
apply
: スポークが残っている場合に呼び出され、UI 要素の値をself.data
構造に戻す際に使用されます。 -
execute
: ユーザーがスポークを離れる場合に呼び出され、スポークの新しい状態に基づいてランタイムの変更を実行する際に使用されます。
これらの関数は、以下のように Hello World アドオンのサンプルに実装されます。
例5.6 更新、適用、および実行メソッドの定義
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 属性に特定の値を設定する必要があります。
例5.7 準備完了、完了、および必須メソッドの定義
@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
の例のアドオンで定義されます。
例5.8 status
プロパティーの定義
@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 below 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
パッケージで見つけることができます。
グラフィカルインターフェイスのサポートモジュールに、必要な方法をすべて含むと、以下のセクションへ進んでテキストベースのユーザーインターフェイスのサポートを追加するか、Anaconda アドオンのデプロイおよびテスト へ進んでアドオンをテストすることができます。