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

我正在尝试为ubuntu Mate编写一些面板应用程序。 我比较熟悉C / C ++和SDL。 我已经看过Mate-University面板应用程序github页面,但我无法让它正常工作/我有一段时间。

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

因为似乎是问这个问题的机会已经有了答案 ,我正在回答这个问题作为对它是如何完成的扩展解释(在python

基本静态指标

由于Ubuntu Mate(15,10)支持指标,因此为Mate编写指标和面板应用程序之间没有太大区别。 因此,使用AppIndicator3 API, 此链接是python基本指示符的良好起点。 链接是一个很好的开始,但不提供有关如何在指标上显示文本的任何信息,更不用说如何更新文本(或图标)。 然而,通过一些补充,这导致指标的基本“框架”如下。 它将显示图标,文本标签和菜单:

在此处输入图像描述

 #!/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来安排在主线程中执行的GUI任务

当我们用GObject.threads_init()GObject.threads_init()替换gobject.threads_init()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() 

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