我需要你的帮助:我正在开发一个小型Java应用程序(Java版本7),它必须最小化到系统托盘中。
我正在使用Class SystemTray,使用SystemTray.isSupported(),然后
SystemTray systemTray = SystemTray.getSystemTray();
ImageIcon icon = new javax.swing.ImageIcon(getClass().getResource("icon.png"));
[...]
systemTray.add(trayIcon);
(当然有弹出窗口)
在Windows上,它运行良好。在XFCE,Xubuntu,没问题,图标正在使用弹出窗口。但是在KDE和Gnome shell上......它不起作用。
(Qt:4.8.6工具等离子:4.11.12)
SystemTray.isSupported()= true,当程序到达该行时: systemTray.add(托盘图标);抓住了一个例外:
托盘过程中出现错误: java.awt.AWTException:无法显示TrayIcon。
因此,图标为白色,当用户点击它时不起作用,没有弹出窗口。
SystemTray.isSupported()= true,图标位于底部的通知区域,但鼠标事件不起作用...
为了解决这些问题,我认为SWT可能是一个好主意。但是当我实现它(上一版本)时,我收到了这个警告:
警告**:无法连接到辅助功能总线:连接失败 to socket / tmp /[...]
它不起作用...... 编辑:不再了,我可以用外部类修复SWT的问题。警告不是由SWT引起的,而是由环境系统引起的(我和终端中的其他应用程序有相同的警告)。
那么现在,我该怎么办?
我认为check environment system与System.getenv("XDG_CURRENT_DESKTOP")
& System.getenv("GDMSESSION")
,然后启用或禁用系统托盘,如果它是KDE或Gnome 3 ...但此解决方案实际上不是好因为它是本地解决方案对于多平台(在我的意思是OS的功能),而不是全局解决方案(所有操作系统的一种方法)......
那么,其他想法?我不知道......有没有办法将嵌入式JWindow定义到系统托盘中?
答案 0 :(得分:2)
我自己也遇到过这个问题,而且我记得我跑出了一堵砖墙,用合法的解决方案将其整理出来。我跟踪问题来调用TrayIcon.addNotify()方法随机失败。我似乎记得这是因为内部的竞争条件是对X11系统的调用花了太长时间才完成所以java方面放弃了。
但是如果你有一个带有不错的显卡的忍者电脑,你可能永远不会遇到这种情况,这可能就是为什么它还没有被修复。我的开发机器速度很慢,所以50%的时间都发生在我身上。
我一起做了 hack 一个快速而又脏的解决方案,其中包括尝试重复调用addNotify(在每次尝试之间暂停),直到成功(或最多次失败)。不幸的是,唯一的方法是通过反射,因为addNotify方法是包私有的。
代码如下:
function build_menu($array, $parent = 0, $level = 0)
{
$ret = '';
foreach($array as $m)
{
if($m['parent_menu'] == $parent)
{
$ret .= '<ul>';
$ret .= '<li>' . $m['menu_link'] . '</li>';
$ret .= $this -> build_menu($array, $m['menu_link'], $level + 1);
$ret .= '</ul>';
}
}
return $ret;
}
要使用它,只需致电:
public class HackyLinuxTrayIconInitialiser extends SwingWorker<Void, TrayIcon> {
private static final int MAX_ADD_ATTEMPTS = 4;
private static final long ADD_ICON_DELAY = 200;
private static final long ADD_FAILED_DELAY = 1000;
private TrayIcon[] icons;
public HackyLinuxTrayIconInitialiser(TrayIcon... ic) {
icons = ic;
}
@Override
protected Void doInBackground() {
try {
Method addNotify = TrayIcon.class.getDeclaredMethod("addNotify", (Class<?>[]) null);
addNotify.setAccessible(true);
for (TrayIcon icon : icons) {
for (int attempt = 1; attempt < MAX_ADD_ATTEMPTS; attempt++) {
try {
addNotify.invoke(icon, (Object[]) null);
publish(icon);
pause(ADD_ICON_DELAY);
break;
} catch (NullPointerException | IllegalAccessException | IllegalArgumentException e) {
System.err.println("Failed to add icon. Giving up.");
e.printStackTrace();
break;
} catch (InvocationTargetException e) {
System.err.println("Failed to add icon, attempt " + attempt);
pause(ADD_FAILED_DELAY);
}
}
}
} catch (NoSuchMethodException | SecurityException | NoSuchFieldException e1) {
Log.err(e1);
}
return null;
}
private void pause(long delay) {
try {
Thread.sleep(delay);
} catch (InterruptedException e1) {
Log.err(e1);
}
}
@Override
protected void process(List<TrayIcon> icons) {
for (TrayIcon icon : icons) {
try {
tray.add(icon);
} catch (AWTException e) {
Log.err(e);
}
}
}
}
我似乎记得当时我无法继续调用SystemTray.add(icon)因为它会离开&#34; ghost&#34;如果我这样做,系统托盘后面的托盘。
希望这有帮助。