Як я можу записати динамічно оновлений додаток / індикатор на панелі?


12

Я намагаюся написати кілька панельних програм для ubuntu Mate. Я знаю C / C ++ і SDL досить добре. Я бачив сторінку github на панелі додатків Mate-University, але я не можу змусити її працювати належним чином / я маю хоч час із цим.

Мені просто цікаво, чи є якийсь простий шлях для написання панельних програм? Я не говорю про використання програми запуску користувальницьких програм, я хотів би додати на панель нову функціональність, але я не впевнений, як це зробити. Підручник або опис написання програм на панелі може бути дуже корисним.

Відповіді:


16

Оскільки на те, що, здається, є приводом задати це питання, вже є відповідь , я відповідаю на це питання як розширене пояснення того, як це робилося (в python)

Основний статичний показник

Оскільки Ubuntu Mate з 15,10 підтримує індикатори, між написанням індикатора та панельним додатком для Mate немає великої різниці. Тому це посилання є хорошою відправною точкою для базового показника python, використовуючи AppIndicator3API. Посилання є приємним початком, але не дає ніякої інформації про те, як відобразити текст на індикаторі, не кажучи вже про те, як оновити текст (або значок). Тим не менш, з кількома доповненнями, це призводить до базового "кадру" індикатора, як показано нижче. На ньому буде показано піктограму, текстову мітку та меню:

введіть тут опис зображення

#!/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()

У рядку AppIndicator3.IndicatorCategory.OTHERкатегорія визначається, як пояснено у цьому (частково застарілому) посиланні . Встановлення потрібної категорії важливо, а.о., щоб поставити індикатор у відповідне положення на панелі.

Основний виклик; як оновити текст індикатора та / або значок

Справжня задача полягає не в тому, як написати основний показник, а як періодично оновлювати текст та / або піктограму вашого індикатора, оскільки ви хочете, щоб він відображав (текстовий) час. Щоб індикатор працював належним чином, ми не можемо просто використовувати threadingдля запуску другого процесу періодичне оновлення інтерфейсу. Ну, насправді ми можемо, але в більш тривалому періоді це призведе до конфліктів, як я з'ясував.

Ось, куди GObjectвходить, щоб, як зазначено в цьому (також застарілому) посиланні :

виклик gobject.threads_init()при ініціалізації програми. Тоді ви запускаєте свої потоки нормально, але переконайтеся, що потоки ніколи не виконують жодних завдань GUI безпосередньо. Замість цього ви використовуєте gobject.idle_addдля планування завдання графічного інтерфейсу, що виконується в основному потоці

Коли ми замінимо gobject.threads_init() на GObject.threads_init()і gobject.idle_addна GObject.idle_add(), ми в значній мірі маємо оновлену версію про те , як запускати потоки в Gtkдодатку. Спрощений приклад, що показує все більшу кількість Мавп:

введіть тут опис зображення

#!/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()

Це принцип. В реальному показнику в цій відповіді і час циклу, і текст індикатора визначалися вторинним модулем, імпортованим у сценарій, але головна думка однакова.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.