Desktopintegrationsbemühungen
| Anke (encarsia) | Auch verfügbar in: English
Inhalt
Desktopintegration: Icon, Headerbar, Kommandozeilenoptionen
(Fortsetzung zum Artikel Gtk.Application)
Glade
Icon
Einem Fenster lässt sich direkt in Glade unter "Allgemein > Darstellung > Symboldatei" ein Icon auswählen. Das Problem dabei ist, dass Glade Bilddateien nur anzeigt, wenn sie sich im selben Verzeichnis wie die Glade-Datei selbst befinden, auch wenn man ein anderes Verzeichnis auswählt.
Am einfachsten behebt man dies, indem man die Gladedatei in einem Texteditor bearbeitet und den (relativen) Pfad zum Icon angibt. Diese Einstellung bleibt auch erhalten, wenn die Datei später wieder mit Glade bearbeitet und gespeichert wird:
<object class="GtkApplicationWindow" id="window"> ... <!-- <property name="icon">duckyou.svg</property> --> <property name="icon">../files/duckyou.svg</property> ...
Headerbar
Die Headerbar wurde mit GNOME 3.10 eingeführt und vereint Titelleiste und Toolbar in einem Widget, d.h neben Titel und Untertitel können rechts und/oder links verschiedene Widgets (Menüs, Buttons) angelegt sowie clientseitige Fensterkontrollknöpfe angezeigt werden.
Die Headerbar ist optional. Möchte man sie nutzen, muss in den Fenstereinstellungen "Allgemein > Darstellung > Klienseitige Fensterdekoration" ausgewählt werden. Daraufhin erscheint im oberen Bereich des Fensters ein reservierter Bereich, in dem die Headerbar platziert wird. Wird die Headerbar außerhalb davon platziert, wird weiterhin zusätzlich die normale Titelleiste angezeigt.
Kommandozeilenoptionen
Gtk.Application stellt die erforderlichen Mittel für anwendungseigene Kommandozeilenoptionen zur Verfügung (Handling command line options in GApplication).
Optionen anlegen
Verfügbare Optionen werden mit der Funktion add_main_option_entries(entrylist)
hinzugefügt. Diese Einträge haben das Format GLib.OptionEntry, welches allerlei Parameter besitzt.
def __init__(self): self.app = Gtk.Application.new("org.application.test", Gio.ApplicationFlags(0)) self.app.add_main_option_entries([ self.create_option_entry("--version", description="Show version numbers and exit"), self.create_option_entry("--setlabel", description="Set label widget", arg=GLib.OptionArg.STRING,), self.create_option_entry("--bollocks", description="Additional test option - exit"), ]) def create_option_entry(self, long_name, short_name=None, flags=0, arg=GLib.OptionArg.NONE, arg_data=None, description=None, arg_description=None): option = GLib.OptionEntry() option.long_name = long_name.lstrip("-") option.short_name = 0 if not short_name else ord(short_name.lstrip("-")) option.flags = flags option.arg = arg option.arg_data = arg_data option.description = description option.arg_description = arg_description return option
Shortnames
Eine Option kann ein aus einem Buchstaben (oder besser gesagt "printable ASCII character different from ‘-‘") bestehenden Synonmym besitzen, den Shortname. Bei der Option --help
ist dies gemeinhin -h
.
Die short_name
-Variable von OptionEntry ist allerdings integer. Die in der Dokumentation nicht ersichtliche Lösung besteht darin, in der Variable die Dezimalkodierung des entsprechenden Zeichens zu übergeben, also etwa 97 für "a". Bei ungültigen Werten wird eine Fehlermeldung ausgegeben. Optionen ohne Shortname erhalten den Wert 0.
Signal verbinden
Der Gtk.Application-eigene "handle-local-options"-Handler verarbeitet die Optionen. Sobald Optionen angelegt sind, wird dieses Signal noch vor dem "startup"-Signal ausgelöst
self.app.connect("handle-local-options", self.on_local_option)
Optionen verarbeiten
Die an die Handler-Funktion übergebene option
ist ein Element der Klasse GLib.VariantDict. Mit contains("option")
lässt sich nach der übergebenen Option suchen.
def on_local_option(self, app, option): if option.contains("option1"): #do something and exit normally return 0 elif option.contains("option2"): #do something different and exit return 0 elif option.contains("option3"): #do more and continue return -1
Ein übergebener String kann extrahiert werden, indem GLib.VariantDict mit end()
in GLib.Variant konvertiert wird, das sich wiederum mit keys()
auslesen lässt:
var = GLib.VariantDict.end(option) option_string = var[var.keys()[0]]
- Ein Return-Wert ist zwingend erforderlich, er entspricht dabei dem Exit-Status:
-1: Anwendung wird weiter ausgeführt
0: erfolgreiche Ausführung, Anwendung wird beendet, "startup/activate" werden nicht ausgeführt
1 bzw. positiver Wert: nicht erfolgreiche Ausführung, Anwendung wird beendet
Optionen übergeben
Die Option, die immer verfügbar ist, ist --help
. Hier werden unter "Anwendungsoptionen" die angelegten Optionen samt Beschreibung aufgeführt. Die Optionen können wie definiert angegeben werden:
$ python script.py --version Python: 3.6.0 GTK+: 3.22.6
oder mit --setlabel
einen String an Gtk.Label übergeben:
$ python script.py --setlabel "I can haz options!"
Listings
Python
#!/usr/bin/python # -*- coding: utf-8 -*- import sys import setproctitle import gi gi.require_version("Gtk", "3.0") from gi.repository import Gtk, Gio, GLib class ExampleApp: def __init__(self): setproctitle.setproctitle("Application test") GLib.set_prgname("testapp") self.app = Gtk.Application.new("org.application.test", Gio.ApplicationFlags(0)) self.app.add_main_option_entries([ self.create_option_entry("--version", description="Show version numbers and exit", ), self.create_option_entry("--setlabel", description="Set label widget", arg=GLib.OptionArg.STRING, ), self.create_option_entry("--bollocks", description="Additional test option - exit", ), ]) self.app.connect("handle-local-options", self.on_local_option) self.app.connect("activate", self.on_app_activate) def on_local_option(self, app, option): self.option_string = "" if option.contains("version"): var = GLib.VariantDict.end(option) print("Python: {}".format(sys.version[:5])) print("GTK+: {}.{}.{}".format(Gtk.MAJOR_VERSION, Gtk.MINOR_VERSION, Gtk.MICRO_VERSION, )) return 0 elif option.contains("bollocks"): return 1 elif option.contains("setlabel"): var = GLib.VariantDict.end(option) self.option_string = var[var.keys()[0]] return -1 def create_option_entry(self, long_name, short_name=None, flags=0, arg=GLib.OptionArg.NONE, arg_data=None, description=None, arg_description=None, ): option = GLib.OptionEntry() option.long_name = long_name.lstrip("-") option.short_name = 0 if not short_name else ord(short_name.lstrip("-")) option.flags = flags option.arg = arg option.arg_data = arg_data option.description = description option.arg_description = arg_description return option def on_app_activate(self, app): builder = Gtk.Builder() builder.add_from_file("15_application.glade") self.obj = builder.get_object self.obj("window").set_application(app) self.obj("label").set_text(self.option_string) self.obj("window").show_all() def run(self, argv): self.app.run(argv) app = ExampleApp() app.run(sys.argv)
Glade
<?xml version="1.0" encoding="UTF-8"?> <!-- Generated with glade 3.20.0 --> <interface> <requires lib="gtk+" version="3.20"/> <object class="GtkMenu" id="menu"> <property name="visible">True</property> <property name="can_focus">False</property> <child> <object class="GtkMenuItem"> <property name="visible">True</property> <property name="can_focus">False</property> <property name="label" translatable="yes">MenuItem 1</property> <property name="use_underline">True</property> </object> </child> <child> <object class="GtkMenuItem"> <property name="visible">True</property> <property name="can_focus">False</property> <property name="label" translatable="yes">MenuItem 2</property> <property name="use_underline">True</property> </object> </child> <child> <object class="GtkMenuItem"> <property name="visible">True</property> <property name="can_focus">False</property> <property name="label" translatable="yes">MenuItem 3</property> <property name="use_underline">True</property> </object> </child> </object> <object class="GtkApplicationWindow" id="window"> <property name="width_request">400</property> <property name="height_request">300</property> <property name="can_focus">False</property> <property name="title" translatable="yes">Titel</property> <property name="icon">../files/duckyou.svg</property> <property name="show_menubar">False</property> <child> <object class="GtkBox"> <property name="visible">True</property> <property name="can_focus">False</property> <property name="orientation">vertical</property> <child> <object class="GtkImage"> <property name="visible">True</property> <property name="can_focus">False</property> <property name="pixbuf">../files/duckyou.svg</property> </object> <packing> <property name="expand">True</property> <property name="fill">True</property> <property name="position">0</property> </packing> </child> <child> <object class="GtkLabel" id="label"> <property name="visible">True</property> <property name="can_focus">False</property> </object> <packing> <property name="expand">False</property> <property name="fill">True</property> <property name="pack_type">end</property> <property name="position">1</property> </packing> </child> <child> <object class="GtkSeparator"> <property name="visible">True</property> <property name="can_focus">False</property> </object> <packing> <property name="expand">False</property> <property name="fill">True</property> <property name="position">2</property> </packing> </child> </object> </child> <child type="titlebar"> <object class="GtkHeaderBar"> <property name="visible">True</property> <property name="can_focus">False</property> <property name="title">Titel</property> <property name="subtitle">Untertitel</property> <property name="show_close_button">True</property> <child> <object class="GtkMenuButton"> <property name="visible">True</property> <property name="can_focus">True</property> <property name="receives_default">True</property> <property name="popup">menu</property> <child> <placeholder/> </child> </object> </child> <child> <object class="GtkButton"> <property name="label">gtk-no</property> <property name="visible">True</property> <property name="can_focus">True</property> <property name="receives_default">True</property> <property name="use_stock">True</property> <property name="always_show_image">True</property> </object> <packing> <property name="pack_type">end</property> <property name="position">2</property> </packing> </child> <child> <object class="GtkButton"> <property name="label">gtk-yes</property> <property name="visible">True</property> <property name="can_focus">True</property> <property name="receives_default">True</property> <property name="use_stock">True</property> <property name="always_show_image">True</property> </object> <packing> <property name="pack_type">end</property> <property name="position">2</property> </packing> </child> </object> </child> </object> </interface>
Kommentare
Comments powered by Disqus