24. Application
Gtk.Application
täcker flera upprepande uppgifter som ett modernt program behöver så som att hantera flera instanser, D-Bus-aktivering, öppna filer, kommandoradstolkning, uppstart/nedstängning, menyhantering, fönsterhantering med mera.
24.1. Åtgärder
Gio.Action
är ett sätt att exponera varje enskild uppgift ditt program eller din komponent gör med ett namn. Dessa åtgärder kan inaktiveras/aktiveras vid körtid och de kan antingen aktiveras eller få ett tillstånd ändrat (om de innehåller tillstånd).
Orsaken för att använda åtgärder är att separera logiken från användargränssnittet. Till exempel så tillåter detta användning av en menyrad i OSX och en kugghjulsmeny i GNOME genom att helt enkelt referera namnet på en åtgärd. Den huvudsakliga implementationen av detta som du kommer att använda är Gio.SimpleAction
som kommer demonstreras senare.
Många klasser så som Gio.MenuItem
och Gtk.ModelButton
stöder egenskaper för att ställa in ett åtgärdsnamn.
Dessa åtgärder kan grupperas tillsammans i en Gio.ActionGroup
och då dessa grupper läggs till i en komponent med Gtk.Widget.insert_action_group()
kommer de få ett prefix. Exempelvis ”win” då de läggs till ett Gtk.ApplicationWindow
. Du kommer använda det fullständiga åtgärdsnamnet då du refererar till det, som ”app.about”, men då du skapar åtgärden kommer den bara vara ”about” tills den läggs till i programmet.
Du kan också väldigt lätt göra tangentbindningar för åtgärder genom att ställa in egenskapen accel i Gio.Menu
-filen eller genom att använda Gtk.Application.set_accels_for_action()
.
24.3. Kommandorad
Då du skapar ditt program tar det en flaggegenskap från Gio.ApplicationFlags
. Med denna kan du låta det hantera allting själv eller ha mer anpassat beteende.
Du kan använda HANDLES_COMMAND_LINE för att tillåta anpassat beteende i Gio.Application.do_command_line()
. Kombinera med Gio.Application.add_main_option()
för att lägga till anpassade alternativ.
Att använda HANDLES_OPEN kommer göra jobbet med att helt enkelt ta filargument åt dig och låta dig hantera det i Gio.Application.do_open()
.
Om ditt program redan är öppet kommer alla dessa sändas till den befintliga instansen om du inte använder NON_UNIQUE för att tillåta flera instanser.
24.4. Exempel

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"><Primary>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)