gpt4 book ai didi

Java SystemTray 图标并不总是有效

转载 作者:塔克拉玛干 更新时间:2023-11-03 03:55:39 25 4
gpt4 key购买 nike

我需要你的帮助:我正在开发一个小的 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 上……它不起作用。

KDE (4.14.1)

(Qt:4.8.6 工具等 ionic :4.11.12)

SystemTray.isSupported() = true 并且当程序到达该行时:systemTray.add(trayIcon);捕获异常:

Error during Tray process: java.awt.AWTException: TrayIcon couldn't be displayed.

因此图标是白色的,当用户点击它时不起作用,没有弹出窗口。

Gnome 外壳 (3.12.2)

SystemTray.isSupported() = true,图标位于底部的通知区域,但鼠标事件不起作用...

为了解决这些问题,我认为 SWT 可能是个好主意。但是当我实现它(上一个版本)时,我收到了这个警告:

WARNING **: Couldn't connect to accessibility bus: Failed to connect to socket /tmp/[...]

而且它不起作用...编辑:不再,我可以用外部类解决 SWT 的问题。该警告不是由 SWT 引起的,而可能是由环境系统引起的(我在终端中的其他应用程序也有相同的警告)。


那么现在,我能做什么?我想check environment system使用 System.getenv("XDG_CURRENT_DESKTOP") & System.getenv("GDMSESSION") 然后启用或禁用系统托盘,如果它是 KDE 或 Gnome 3...但是这个解决方案并不是真的,因为它是针对多平台的本地解决方案(我的意思是操作系统的功能),而不是全局 解决方案(适用于所有操作系统的一种方法)...

那么,还有其他想法吗?我不知道...有没有办法将嵌入式 JWindow 定义到系统托盘中?

最佳答案

我自己也遇到过这个问题,我记得我在用合法的解决方案解决这个问题时遇到了困难。我将问题追溯到对 TrayIcon.addNotify() 方法的调用随机失败。我似乎记得这是因为内部竞争条件导致对 X11 系统的调用花费太长时间才能完成,因此 Java 端放弃了。

但是如果你有一台带有像样显卡的忍者 PC,你可能永远不会遇到这种情况,这可能就是它尚未修复的原因。我的开发机器运行缓慢,所以大约 50% 的时间都发生在我身上。

我确实 破解 了一个快速而肮脏的解决方案,其中涉及尝试重复调用 addNotify(每次尝试之间暂停)直到成功(或失败次数达到最大值)。不幸的是,唯一的方法是通过反射,因为 addNotify 方法是包私有(private)的。

代码如下:

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);
}
}
}
}

要使用它,只需调用:

if (<OS is Linux>) {
new HackyLinuxTrayIconInitialiser(ticon, micon, licon).execute();
} else {
try {
tray.add(ticon);
tray.add(micon);
tray.add(licon);
} catch (AWTException e) {
Log.err(e);
}
}

我似乎记得当时我不能一直调用 SystemTray.add(icon),因为如果我这样做,它会在系统托盘上留下“幽灵”trayicons。

希望这对您有所帮助。

关于Java SystemTray 图标并不总是有效,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29995727/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com