Bagaimana saya bisa menulis aplikasi / indikator panel yang diperbarui secara dinamis?

12

Saya mencoba menulis beberapa aplikasi panel untuk ubuntu Mate. Saya tahu C / C ++, dan SDL cukup baik. Saya telah melihat halaman panel aplikasi Mate-University github, tetapi saya tidak dapat membuatnya berfungsi dengan benar / Saya memiliki waktu yang lama dengannya.

Saya hanya ingin tahu, apakah ada cara mudah untuk menulis aplikasi panel? Saya tidak berbicara tentang menggunakan peluncur aplikasi khusus, saya ingin menambahkan fungsi baru, ke panel, tetapi saya tidak yakin bagaimana caranya. Tutorial, atau deskripsi tentang penulisan aplikasi panel bisa sangat membantu.

j0h
sumber

Jawaban:

16

Karena apa yang tampaknya merupakan kesempatan untuk mengajukan pertanyaan ini sudah memiliki jawaban , saya menjawab pertanyaan ini sebagai penjelasan panjang lebar tentang bagaimana hal itu dilakukan (dalam python)

Indikator statis dasar

Karena Ubuntu Mate, mulai 15,10, mendukung indikator, tidak ada banyak perbedaan antara penulisan indikator dan aplikasi panel untuk Mate. Oleh karena itu, tautan ini adalah titik awal yang baik untuk indikator dasar dalam python, menggunakan AppIndicator3API. Tautan ini merupakan awal yang baik, tetapi tidak memberikan informasi tentang cara menampilkan teks pada indikator, apalagi cara memperbarui teks (atau ikon). Namun demikian, dengan beberapa tambahan, ini mengarah ke "bingkai" dasar dari indikator seperti di bawah ini. Ini akan menampilkan ikon, label teks dan menu:

masukkan deskripsi gambar di sini

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

Pada baris tersebut AppIndicator3.IndicatorCategory.OTHER, kategori didefinisikan, seperti yang dijelaskan dalam tautan (sebagian usang) ini . Mengatur kategori yang tepat itu penting, ao untuk meletakkan indikator pada posisi yang sesuai di panel.

Tantangan utama; cara memperbarui teks indikator dan / atau ikon

Tantangan sebenarnya bukanlah bagaimana menulis indikator dasar, tetapi bagaimana memperbarui teks dan / atau ikon indikator Anda secara berkala , karena Anda ingin agar indikator itu menunjukkan waktu (tekstual). Untuk membuat indikator berfungsi dengan baik, kita tidak bisa hanya menggunakan threadinguntuk memulai proses kedua untuk memperbarui antarmuka secara berkala. Sebenarnya kita bisa, tetapi dalam jangka panjang, itu akan menimbulkan konflik, seperti yang saya ketahui.

Di sinilah GObjectmasuk, ke, seperti yang dimasukkan dalam tautan ini (juga ketinggalan zaman) :

panggilan gobject.threads_init()di inisialisasi aplikasi. Kemudian Anda memulai utas secara normal, tetapi pastikan utas tidak pernah melakukan tugas GUI secara langsung. Sebaliknya, Anda menggunakan gobject.idle_adduntuk menjadwalkan tugas GUI untuk dieksekusi di utas utama

Ketika kami mengganti gobject.threads_init() dengan GObject.threads_init()dan gobject.idle_addoleh GObject.idle_add(), kami memiliki versi terbaru tentang cara menjalankan utas dalam suatu Gtkaplikasi. Contoh yang disederhanakan, menunjukkan peningkatan jumlah Monyet:

masukkan deskripsi gambar di sini

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

Itulah prinsipnya. Dalam indikator aktual dalam jawaban ini , baik waktu putaran dan teks indikator ditentukan oleh modul sekunder, yang diimpor dalam skrip, tetapi gagasan utamanya adalah sama.

Yakub Vlijm
sumber