Poiché quella che sembra essere l'occasione per porre questa domanda ha già una risposta , rispondo a questa domanda come una spiegazione estesa su come è stata fatta (in python
)
Indicatore statico di base
Poiché Ubuntu Mate, dalle 15,10, supporta gli indicatori, non c'è molta differenza tra la scrittura di un indicatore e un'app pannello per Mate. Pertanto, questo collegamento è un buon punto di partenza per un indicatore di base python
, utilizzando l' AppIndicator3
API. Il collegamento è un buon inizio, ma non fornisce alcuna informazione su come mostrare il testo sull'indicatore, figuriamoci su come aggiornare il testo (o l'icona). Tuttavia, con alcune aggiunte, questo porta ad un "frame" di base di un indicatore come di seguito. Mostrerà un'icona, un'etichetta di testo e 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()
Nella riga AppIndicator3.IndicatorCategory.OTHER
, viene definita la categoria, come spiegato in questo collegamento (parzialmente obsoleto) . È importante impostare la giusta categoria, anche per mettere l'indicatore in una posizione appropriata nel pannello.
La sfida principale; come aggiornare il testo dell'indicatore e / o l'icona
La vera sfida non è come scrivere un indicatore di base, ma come aggiornare periodicamente il testo e / o l'icona del tuo indicatore, poiché vuoi che mostri il tempo (testuale). Per far funzionare correttamente l'indicatore, non possiamo semplicemente usare threading
per avviare un secondo processo per aggiornare periodicamente l'interfaccia. Bene, in realtà possiamo, ma a lungo termine, porterà a conflitti, come ho scoperto.
Ecco dove GObject
entra, a, come viene inserito in questo link (anche obsoleto) :
chiamare gobject.threads_init()
all'inizializzazione dell'applicazione. Quindi avvii i thread normalmente, ma assicurati che i thread non eseguano direttamente alcuna attività della GUI. Invece, si utilizza gobject.idle_add
per pianificare l'attività della GUI da eseguire nel thread principale
Quando sostituiamo gobject.threads_init()
da GObject.threads_init()
e gobject.idle_add
per GObject.idle_add()
, abbiamo praticamente abbiamo la versione aggiornata di come eseguire thread in un Gtk
applicazione. Un esempio semplificato, che mostra un numero crescente di scimmie:
#!/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()
Questo è il principio. Nell'indicatore reale in questa risposta , sia il tempo di ciclo che il testo dell'indicatore sono stati determinati da un modulo secondario, importato nello script, ma l'idea principale è la stessa.