我正在尝试为 ubuntu Mate 编写一些面板应用程序。我对 C/C++ 和 SDL 相当了解。我看过 Mate-University 面板应用程序 github 页面,但我无法让它正常工作/我花了很长时间来研究它。
我只是想知道,是否有一些简单的方法来编写面板应用程序?我说的不是使用自定义应用程序启动器,我想向面板添加新功能,但我不知道该怎么做。关于编写面板应用程序的教程或描述可能会很有帮助。
答案1
因为似乎已经到了提出这个问题的时机有答案,我回答这个问题是为了解释它是如何完成的(在python
)
基本的静止的指标
由于 Ubuntu Mate 从 15.10 开始支持指标,因此为 Mate 编写指标和面板应用程序之间没有太大区别。因此,此链接python
是使用API 来开始使用中的基本指标的良好起点AppIndicator3
。该链接是一个不错的开始,但没有提供任何有关如何在指标上显示文本的信息,更不用说如何更新文本(或图标)。不过,添加一些内容后,就可以得到如下所示的指示器的基本“框架”。它将显示一个图标、一个文本标签和一个菜单:
#!/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()
byGObject.threads_init()
和gobject.idle_add
by替换后GObject.idle_add()
,我们基本上就拥有了如何在Gtk
应用程序中运行线程的更新版本。一个简化的示例,显示了越来越多的 Monkeys:
#!/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()
这就是原理。在实际指标中这个答案,循环时间和指示文本均由脚本中导入的辅助模块确定,但主要思想是相同的。