Étant donné que ce qui semble être l'occasion de poser cette question a déjà une réponse , je réponds à cette question comme une explication détaillée de la façon dont cela a été fait (en python
)
Indicateur statique de base
Comme Ubuntu Mate, à partir de 15,10, prend en charge les indicateurs, il n'y a pas beaucoup de différence entre l'écriture d'un indicateur et une application de panneau pour Mate. Par conséquent, ce lien est un bon point de départ pour un indicateur de base dans python
, en utilisant l' AppIndicator3
API. Le lien est un bon début, mais ne fournit aucune information sur la façon d'afficher du texte sur l'indicateur, et encore moins sur la façon de mettre à jour le texte (ou l'icône). Néanmoins, avec quelques ajouts, cela conduit à un "cadre" de base d'un indicateur comme ci-dessous. Il affichera une icône, une étiquette de texte et un menu:
#!/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()
Dans la ligne AppIndicator3.IndicatorCategory.OTHER
, la catégorie est définie, comme expliqué dans ce lien (partiellement obsolète) . Il est important de définir la bonne catégorie, notamment pour placer l'indicateur dans une position appropriée dans le panneau.
Le principal défi; comment mettre à jour le texte et / ou l'icône de l'indicateur
Le vrai défi n'est pas de savoir comment écrire un indicateur de base, mais comment mettre à jour périodiquement le texte et / ou l'icône de votre indicateur, car vous voulez qu'il affiche l'heure (textuelle). Pour que l'indicateur fonctionne correctement, nous ne pouvons pas simplement utiliser threading
pour démarrer un deuxième processus de mise à jour périodique de l'interface. Eh bien, en fait, nous le pouvons, mais à plus long terme, cela entraînera des conflits, comme je l'ai découvert.
Voici où GObject
entre en jeu, comme il est mis dans ce lien (également obsolète) :
appeler gobject.threads_init()
à l'initialisation de l'applicaiton. Ensuite, vous lancez vos threads normalement, mais assurez-vous que les threads n'effectuent jamais aucune tâche GUI directement. Au lieu de cela, vous utilisez gobject.idle_add
pour planifier l'exécution de la tâche GUI dans le thread principal
Lorsque nous remplaçons gobject.threads_init()
par GObject.threads_init()
et gobject.idle_add
par GObject.idle_add()
, nous avons à peu près la version mise à jour de la façon d'exécuter les threads dans une Gtk
application. Un exemple simplifié, montrant un nombre croissant de singes:
#!/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()
Voilà le principe. Dans l'indicateur réel de cette réponse , le temps de boucle et le texte de l'indicateur ont été déterminés par un module secondaire, importé dans le script, mais l'idée principale est la même.