如何编写动态更新的面板应用程序/指标?

j0h*_*j0h 12 panel python programming c++ mate

我正在尝试为 ubuntu Mate 编写一些面板应用程序。我相当了解 C/C++ 和 SDL。我看过 Mate-University 面板应用程序 github 页面,但我无法让它正常工作/我有一段时间使用它。

我只是想知道,是否有一些简单的途径来编写面板应用程序?我不是在谈论使用自定义应用程序启动器,我想向面板添加新功能,但我不确定如何添加。有关编写面板应用程序的教程或描述可能非常有用。

Jac*_*ijm 18

由于提出这个问题的机会似乎已经有了答案,因此我将回答这个问题作为对其如何完成的扩展解释(在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()
Run Code Online (Sandbox Code Playgroud)

在该行中AppIndicator3.IndicatorCategory.OTHER,定义了类别,如此(部分过时的)链接中所述。设置正确的类别很重要,ao 将指标放在面板中的适当位置。

主要挑战;如何更新指示器文本和/或图标

真正的挑战不是如何编写基本指标,而是如何定期更新指标的文本和/或图标,因为您希望它显示(文本)时间。为了使指标正常工作,我们不能简单地使用threading启动第二个进程来定期更新界面。嗯,实际上我们可以,但从长远来看,这会导致冲突,正如我发现的那样。

这是GObject进来的地方,因为它放在这个(也过时的)链接中

gobject.threads_init()在应用程序初始化时调用。然后正常启动线程,但要确保线程从不直接执行任何 GUI 任务。相反,您使用gobject.idle_add调度 GUI 任务在主线程中执行

当我们替换gobject.threads_init() byGObject.threads_init()gobject.idle_addby 时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()
Run Code Online (Sandbox Code Playgroud)

这就是原则。在此答案的实际指标中,循环时间和指标文本均由脚本中导入的辅助模块确定,但主要思想是相同的。