it-swarm.com.de

Wie kann ich eine dynamisch aktualisierte Panel-App / Anzeige schreiben?

Ich versuche, einige Panel-Apps für Ubuntu Mate zu schreiben. Ich kenne C/C++ und SDL ziemlich gut. Ich habe die Github-Seite für Panel-Apps von Mate-University gesehen, aber ich kann sie nicht richtig zum Laufen bringen/Ich habe eine Bedenkzeit damit.

Ich frage mich nur, ob es eine einfache Möglichkeit gibt, Panel-Apps zu schreiben. Ich spreche nicht über die Verwendung des benutzerdefinierten Anwendungsstarts. Ich möchte dem Panel neue Funktionen hinzufügen, bin mir aber nicht sicher, wie. Ein Tutorial oder eine Beschreibung zum Schreiben von Panel-Apps kann sehr hilfreich sein.

10
j0h

Da dies die Gelegenheit zu sein scheint, diese Frage bereits zu stellen hat eine Antwort , beantworte ich diese Frage als eine erweiterte Erklärung, wie es gemacht wurde (in python).

Grundlegender statischer Indikator

Da Ubuntu Mate ab Version 15.10 Indikatoren unterstützt, gibt es keinen großen Unterschied zwischen dem Schreiben eines Indikators und einer Panel-App für Mate. Daher ist dieser Link ein guter Ausgangspunkt für einen Basisindikator in python unter Verwendung der AppIndicator3-API. Der Link ist ein guter Anfang, enthält jedoch keine Informationen zum Anzeigen von Text auf dem Indikator, geschweige denn zum Aktualisieren des Texts (oder Symbols ). Trotzdem führt dies mit einigen Ergänzungen zu einem grundlegenden "Rahmen" eines Indikators wie folgt. Es wird ein Symbol, eine Textbeschriftung und ein Menü angezeigt:

enter image description here

#!/usr/bin/env python3
import signal
import gi
gi.require_version('Gtk', '3.0')
gi.require_version('AppIndicator3', '0.1')
from gi.repository import Gtk, AppIndicator3

class Indicator():
    def __init__(self):
        self.app = 'test123'
        iconpath = "/opt/abouttime/icon/indicator_icon.png"
        self.indicator = AppIndicator3.Indicator.new(
            self.app, iconpath,
            AppIndicator3.IndicatorCategory.OTHER)
        self.indicator.set_status(AppIndicator3.IndicatorStatus.ACTIVE)       
        self.indicator.set_menu(self.create_menu())
        self.indicator.set_label("1 Monkey", self.app)

    def create_menu(self):
        menu = Gtk.Menu()
        # menu item 1
        item_1 = Gtk.MenuItem('Menu item')
        # item_about.connect('activate', self.about)
        menu.append(item_1)
        # separator
        menu_sep = Gtk.SeparatorMenuItem()
        menu.append(menu_sep)
        # quit
        item_quit = Gtk.MenuItem('Quit')
        item_quit.connect('activate', self.stop)
        menu.append(item_quit)

        menu.show_all()
        return menu

    def stop(self, source):
        Gtk.main_quit()

Indicator()
signal.signal(signal.SIGINT, signal.SIG_DFL)
Gtk.main()

In der Zeile AppIndicator3.IndicatorCategory.OTHER wird die Kategorie definiert, wie in dieser (teilweise veraltete) Link erläutert. Das Einstellen der richtigen Kategorie ist wichtig. um den Indikator an einer geeigneten Position im Panel zu platzieren.

Die Hauptherausforderung; So aktualisieren Sie den Anzeigetext und/oder das Symbol

Die eigentliche Herausforderung besteht nicht darin, einen Basisindikator zu schreiben, sondern den Text und/oder das Symbol Ihres Indikators regelmäßig zu aktualisieren , da Sie dies möchten es zeigt die (textuelle) Zeit. Damit die Anzeige ordnungsgemäß funktioniert, können wir nicht einfach threading verwenden, um einen zweiten Prozess zum regelmäßigen Aktualisieren der Schnittstelle zu starten. Eigentlich können wir das, aber auf längere Sicht wird es zu Konflikten kommen, wie ich herausgefunden habe.

Hier kommt GObject ins Spiel, wie es heißt in diesem (auch veralteten) Link :

gobject.threads_init() bei der Initialisierung der Anwendung aufrufen. Anschließend starten Sie Ihre Threads normal, stellen jedoch sicher, dass die Threads keine GUI-Aufgaben direkt ausführen. Stattdessen verwenden Sie gobject.idle_add, um die Ausführung der GUI-Aufgabe im Hauptthread zu planen .

Wenn wir gobject.threads_init() durch GObject.threads_init() und gobject.idle_add durch GObject.idle_add() ersetzen, haben wir so ziemlich die aktualisierte Version, wie Threads in einer Gtk Anwendung ausgeführt werden. Ein vereinfachtes Beispiel, das eine zunehmende Anzahl von Affen zeigt:

enter image description here

#!/usr/bin/env python3
import signal
import gi
gi.require_version('Gtk', '3.0')
gi.require_version('AppIndicator3', '0.1')
from gi.repository import Gtk, AppIndicator3, GObject
import time
from threading import Thread

class Indicator():
    def __init__(self):
        self.app = 'test123'
        iconpath = "/opt/abouttime/icon/indicator_icon.png"
        self.indicator = AppIndicator3.Indicator.new(
            self.app, iconpath,
            AppIndicator3.IndicatorCategory.OTHER)
        self.indicator.set_status(AppIndicator3.IndicatorStatus.ACTIVE)       
        self.indicator.set_menu(self.create_menu())
        self.indicator.set_label("1 Monkey", self.app)
        # the thread:
        self.update = Thread(target=self.show_seconds)
        # daemonize the thread to make the indicator stopable
        self.update.setDaemon(True)
        self.update.start()

    def create_menu(self):
        menu = Gtk.Menu()
        # menu item 1
        item_1 = Gtk.MenuItem('Menu item')
        # item_about.connect('activate', self.about)
        menu.append(item_1)
        # separator
        menu_sep = Gtk.SeparatorMenuItem()
        menu.append(menu_sep)
        # quit
        item_quit = Gtk.MenuItem('Quit')
        item_quit.connect('activate', self.stop)
        menu.append(item_quit)

        menu.show_all()
        return menu

    def show_seconds(self):
        t = 2
        while True:
            time.sleep(1)
            mention = str(t)+" Monkeys"
            # apply the interface update using  GObject.idle_add()
            GObject.idle_add(
                self.indicator.set_label,
                mention, self.app,
                priority=GObject.PRIORITY_DEFAULT
                )
            t += 1

    def stop(self, source):
        Gtk.main_quit()

Indicator()
# this is where we call GObject.threads_init()
GObject.threads_init()
signal.signal(signal.SIGINT, signal.SIG_DFL)
Gtk.main()

Das ist das Prinzip. In der tatsächlichen Anzeige in diese Antwort wurden sowohl die Schleifenzeit als auch der Anzeigetext von einem sekundären Modul bestimmt, das in das Skript importiert wurde, aber die Hauptidee ist dieselbe.

14
Jacob Vlijm