24. Application

Gtk.Application abrange muitas tarefas repetitivas que um aplicativo moderno precisa, como manipular várias instâncias, ativação do D-Bus, abertura de arquivos, análise de linha de comando, inicialização/desligamento, gerenciamento de menus, gerenciamento de janelas e muito mais.

24.1. Ações

Gio.Action é uma maneira de expor qualquer tarefa que seu aplicativo ou widget fizer por um nome. Essas ações podem ser desabilitadas/habilitadas no tempo de execução e podem ser ativadas ou ter um estado alterado (se elas contiverem estado).

O motivo para usar ações é separar a lógica da interface do usuário. Por exemplo, isso permite usar uma barra de menu no OSX e um menu de engrenagem no GNOME, simplesmente referenciando o nome de uma ação. A principal implementação que você estará usando é Gio.SimpleAction que será mostrado mais tarde.

Muitas classes, como Gio.MenuItem e Gtk.ModelButton suportam propriedades para definir um nome de ação.

Estas ações podem ser agrupadas em um Gio.ActionGroup e quando esses grupos são adicionados a um widget com Gtk.Widget.insert_action_group(), eles ganharão um prefixo. Tal como “win” quando adicionado a um Gtk.ApplicationWindow. Você usará o nome completo da ação ao fazer referência a ele, como “app.about”, mas ao criar a ação, ela ficará “about” até ser adicionada ao aplicativo.

Você também pode facilmente criar keybindings para ações definindo a propriedade accel no arquivo Gio.Menu ou usando Gtk.Application.set_accels_for_action().

24.3. Linha de comando

Ao criar seu aplicativo, ele recebe uma propriedade de flag de Gio.ApplicationFlags. Usando isso, você pode permitir que ele manipule tudo sozinho ou tenha um comportamento mais personalizado.

Você pode usar o HANDLES_COMMAND_LINE para permitir um comportamento customizado em Gio.Application.do_command_line(). Em combinação com Gio.Application.add_main_option() para adicionar opções personalizadas.

Usar HANDLES_OPEN fará o trabalho de simplesmente pegar argumentos de arquivo para você e permitir que você os manipule em Gio.Application.do_open().

Se o seu aplicativo já estiver aberto, todos serão enviados para a instância existente, a menos que você use NON_UNIQUE para permitir várias instâncias.

24.4. Exemplo

_images/application_example.png
  1import sys
  2
  3import gi
  4
  5gi.require_version("Gtk", "3.0")
  6from gi.repository import GLib, Gio, Gtk
  7
  8# This would typically be its own file
  9MENU_XML = """
 10<?xml version="1.0" encoding="UTF-8"?>
 11<interface>
 12  <menu id="app-menu">
 13    <section>
 14      <attribute name="label" translatable="yes">Change label</attribute>
 15      <item>
 16        <attribute name="action">win.change_label</attribute>
 17        <attribute name="target">String 1</attribute>
 18        <attribute name="label" translatable="yes">String 1</attribute>
 19      </item>
 20      <item>
 21        <attribute name="action">win.change_label</attribute>
 22        <attribute name="target">String 2</attribute>
 23        <attribute name="label" translatable="yes">String 2</attribute>
 24      </item>
 25      <item>
 26        <attribute name="action">win.change_label</attribute>
 27        <attribute name="target">String 3</attribute>
 28        <attribute name="label" translatable="yes">String 3</attribute>
 29      </item>
 30    </section>
 31    <section>
 32      <item>
 33        <attribute name="action">win.maximize</attribute>
 34        <attribute name="label" translatable="yes">Maximize</attribute>
 35      </item>
 36    </section>
 37    <section>
 38      <item>
 39        <attribute name="action">app.about</attribute>
 40        <attribute name="label" translatable="yes">_About</attribute>
 41      </item>
 42      <item>
 43        <attribute name="action">app.quit</attribute>
 44        <attribute name="label" translatable="yes">_Quit</attribute>
 45        <attribute name="accel">&lt;Primary&gt;q</attribute>
 46    </item>
 47    </section>
 48  </menu>
 49</interface>
 50"""
 51
 52
 53class AppWindow(Gtk.ApplicationWindow):
 54    def __init__(self, *args, **kwargs):
 55        super().__init__(*args, **kwargs)
 56
 57        # This will be in the windows group and have the "win" prefix
 58        max_action = Gio.SimpleAction.new_stateful(
 59            "maximize", None, GLib.Variant.new_boolean(False)
 60        )
 61        max_action.connect("change-state", self.on_maximize_toggle)
 62        self.add_action(max_action)
 63
 64        # Keep it in sync with the actual state
 65        self.connect(
 66            "notify::is-maximized",
 67            lambda obj, pspec: max_action.set_state(
 68                GLib.Variant.new_boolean(obj.props.is_maximized)
 69            ),
 70        )
 71
 72        lbl_variant = GLib.Variant.new_string("String 1")
 73        lbl_action = Gio.SimpleAction.new_stateful(
 74            "change_label", lbl_variant.get_type(), lbl_variant
 75        )
 76        lbl_action.connect("change-state", self.on_change_label_state)
 77        self.add_action(lbl_action)
 78
 79        self.label = Gtk.Label(label=lbl_variant.get_string(), margin=30)
 80        self.add(self.label)
 81        self.label.show()
 82
 83    def on_change_label_state(self, action, value):
 84        action.set_state(value)
 85        self.label.set_text(value.get_string())
 86
 87    def on_maximize_toggle(self, action, value):
 88        action.set_state(value)
 89        if value.get_boolean():
 90            self.maximize()
 91        else:
 92            self.unmaximize()
 93
 94
 95class Application(Gtk.Application):
 96    def __init__(self, *args, **kwargs):
 97        super().__init__(
 98            *args,
 99            application_id="org.example.myapp",
100            flags=Gio.ApplicationFlags.HANDLES_COMMAND_LINE,
101            **kwargs
102        )
103        self.window = None
104
105        self.add_main_option(
106            "test",
107            ord("t"),
108            GLib.OptionFlags.NONE,
109            GLib.OptionArg.NONE,
110            "Command line test",
111            None,
112        )
113
114    def do_startup(self):
115        Gtk.Application.do_startup(self)
116
117        action = Gio.SimpleAction.new("about", None)
118        action.connect("activate", self.on_about)
119        self.add_action(action)
120
121        action = Gio.SimpleAction.new("quit", None)
122        action.connect("activate", self.on_quit)
123        self.add_action(action)
124
125        builder = Gtk.Builder.new_from_string(MENU_XML, -1)
126        self.set_app_menu(builder.get_object("app-menu"))
127
128    def do_activate(self):
129        # We only allow a single window and raise any existing ones
130        if not self.window:
131            # Windows are associated with the application
132            # when the last one is closed the application shuts down
133            self.window = AppWindow(application=self, title="Main Window")
134
135        self.window.present()
136
137    def do_command_line(self, command_line):
138        options = command_line.get_options_dict()
139        # convert GVariantDict -> GVariant -> dict
140        options = options.end().unpack()
141
142        if "test" in options:
143            # This is printed on the main instance
144            print("Test argument recieved: %s" % options["test"])
145
146        self.activate()
147        return 0
148
149    def on_about(self, action, param):
150        about_dialog = Gtk.AboutDialog(transient_for=self.window, modal=True)
151        about_dialog.present()
152
153    def on_quit(self, action, param):
154        self.quit()
155
156
157if __name__ == "__main__":
158    app = Application()
159    app.run(sys.argv)

24.5. Veja também