5.10. GUI(Add-On 그래픽 사용자 인터페이스)에 대한 지원 추가

이 섹션에서는 다음과 같은 고급 단계를 수행하여 추가 기능의 GUI(그래픽 사용자 인터페이스)에 지원을 추가하는 방법에 대해 설명합니다.

  1. Normalspoke 클래스에 필요한 속성 정의
  2. __init__초기화 방법 정의
  3. 새로 고침 정의,적용, 실행 방법
  4. 상태준비 완료필수 속성을 정의합니다.

사전 요구 사항

  • 애드온에 Kickstart 지원이 포함되어 있습니다. Anaconda 애드온 구조를 참조하십시오.
  • Anaconda 에 고유한 Gtk 위젯(예: SpokeWindow )이 포함된 anaconda-widgets 및 anaconda-widgets-devel 패키지를 설치합니다.

절차

  • 다음 예와 같이 Add-on 그래픽 사용자 인터페이스(GPU)에 대한 지원을 추가하는 데 필요한 모든 정의로 다음 모듈을 생성합니다.

예 5.4. 일반 스포크 클래스에 필요한 속성 정의:

# 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 파일에 정의된 위젯을 참조합니다. 다른 주목할 만한 두 가지 속성이 있습니다.

  • category, com_example_hello_world.gui.categories 모듈의 Helloworld Category 클래스에서 가져온 값을 갖습니다. add-ons 경로가 sys.path에 있어 com_example_hello_world 패키지에서 값을 가져올 수 있도록 Helloworld Category that add-ons is in sys.path so that values can be imported from the com_example_hello_world package. category 속성은 변환에 대한 문자열을 표시하는 N_ 함수 이름의 일부이지만 이후 단계에서 번역이 이루어지므로 문자열의 번역되지 않은 버전을 반환합니다.
  • name, 해당 정의에 하나의 밑줄이 포함되어 있습니다. title 속성은 title 자체의 시작을 표시하고 Alt+H 키보드 바로 가기를 사용하여 대화 상자를 연결할 수 있도록 합니다.

일반적으로 클래스 정의의 헤더와 클래스 특성 정의는 클래스의 인스턴스를 초기화하는 생성자입니다. Anaconda 그래픽 인터페이스 오브젝트의 경우 새 인스턴스를 초기화하는 방법에는 __init__ 메서드와 initialize 메서드라는 두 가지 방법이 있습니다.

이러한 기능 뒤에 있는 이유는 GUI 객체가 한 번에 메모리에 생성될 수 있고 스포크 초기화가 시간 소모될 수 있기 때문에 다른 시간에 완전히 초기화될 수 있기 때문입니다. 따라서 __init__ 메서드는 상위의 __init__ 메서드만 호출해야 하며, 예를 들어, GPU가 아닌 특성을 초기화해야 합니다. 반면 설치 프로그램의 그래픽 사용자 인터페이스가 초기화될 때 호출되는 initialize 메서드는 spoke의 전체 초기화를 완료해야 합니다.

Hello World 애드온 예에서 다음과 같이 이 두 가지 방법을 정의합니다. __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__ 메서드에 전달된 data 매개 변수는 모든 데이터가 저장된 Kickstart 파일의 메모리 내 트리와 같습니다. RuntimeClass의 __init__ 메서드 중 하나에서 이 메서드는 해당 구조를 읽고 수정할 수 있도록 하는 self.data 특성에 저장됩니다.

참고

스토리지 오브젝트는 RHEL9에서 더 이상 사용할 수 없습니다. 추가 기능이 스토리지 구성과 상호 작용해야 하는 경우 Storage DBus 모듈을 사용합니다.

HelloworldData 클래스는 Hello World 애드온 예제에 이미 정의되어 있기 때문에 이 애드온에 대한 subtree가 이미 self.data에 있습니다. 클래스의 루트는 self.data.addons.com_example_hello_world 로 사용할 수 있습니다.

RuntimeClass의 __init__ 가 수행하는 또 다른 작업은 대화 상자의 .glade 파일을 사용하여 GtkBuilder의 인스턴스를 초기화하고 self.builder 로 저장하는 것입니다. 초기화 방법은 이 방법을 사용하여 Kickstart 파일의 %addon 섹션에서 텍스트를 표시하고 수정하는 데 사용되는 GtkTextEntry 를 가져옵니다.

spoke이 생성될 때 __init__initialize 메서드는 모두 중요합니다. 그러나 스포크의 주요 역할은 대화된 값의 표시 및 집합을 변경하거나 검토하려는 사용자가 방문하는 것입니다. 이를 활성화하려면 다음 세 가지 다른 방법을 사용할 수 있습니다.

  • 새로 고침 - 스포크를 방문할 때 호출됩니다. 이 방법은 spoke의 상태를 새로 고침하여 표시된 데이터가 내부 데이터 구조와 일치하는지 확인하기 위해 자체.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

여러 가지 추가 방법을 사용하여 spoke의 상태를 제어할 수 있습니다.

  • Ready - 스포크를 방문할 준비가 되었는지 여부를 결정합니다. 값이 "False"이면 패키지 소스가 구성되기 전에 패키지 선택 대화 상자에 액세스할 수 없습니다.
  • 완료 - 대화가 완료되었는지 확인합니다.
  • 필수 - 대화 상자(예: 설치 대상 대화)가 필수인지 여부를 결정합니다. 이 대화는 자동 파티셔닝을 사용하려는 경우에도 항상 방문해야 합니다.

이러한 모든 속성은 설치 프로세스의 현재 상태에 따라 동적으로 결정해야 합니다.

다음은 Hello World 애드온에서 이러한 메서드의 샘플 구현으로, Helloworld Data 클래스의 텍스트 특성에 특정 값을 설정해야 합니다.

예 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

이러한 속성이 정의되면 스포크는 접근성과 완전성을 제어할 수 있지만, 내에 구성된 값의 요약을 제공할 수 없습니다. spoke를 방문하여 이 구성이 어떻게 구성되어 있는지 확인해야 합니다. 이는 바람직하지 않을 수 있습니다. 따라서 status 라는 추가 속성이 있습니다. 이 속성에는 구성된 값에 대한 간단한 요약이 포함된 한 줄의 텍스트가 포함되어 있으며, 이는 스포크 제목에 따라 허브에 표시할 수 있습니다.

status 속성은 다음과 같이 Hello World 예제 애드온에 정의되어 있습니다.

예 5.8. 상태 속성 정의

@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))

예제에 설명된 모든 속성을 정의하면 애드온에서 그래픽 사용자 인터페이스(GPU)와 Kickstart를 표시하는 완전 지원이 제공됩니다.

참고

여기에 설명 된 예제는 매우 간단 하 고 컨트롤을 포함 하지 않습니다. Python Gtk 프로그래밍에 대한 지식이 GUI에서 기능적인 대화식 스포크를 개발해야합니다.

한 가지 주목할 만한 제한 사항은 각 대화의 자체 기본 창 - SpokeWindow 위젯의 인스턴스가 있어야한다는 것입니다. 이 위젯은 Anaconda에 관련된 다른 위젯과 함께 anaconda-widgets 패키지에 있습니다. anaconda-widgets-devel 패키지에서 GUI 지원과 같은 추가 기능 개발에 필요한 다른 파일을 찾을 수 있습니다.

그래픽 인터페이스 지원 모듈에 필요한 모든 방법이 포함되어 있으면 다음 섹션을 계속 사용하여 텍스트 기반 사용자 인터페이스에 대한 지원을 추가하거나 Anaconda 애드온 배포 및 테스트를 계속 수행하고 애드온을 테스트할 수 있습니다.