微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

如何防止TrayIconpopup窗口占用整个调度程序线程

我有一个Java应用程序,使用JFrame以及TrayIcon ,我添加一个PopupMenu的TrayIcon 。

当我点击TrayIconpopup菜单出现,但只要PopupMenu可见,主框架就会冻结。

我的第一个想法是事件调度线程被某人占用。 所以我写了一个小的示例应用程序,它使用了一个swing工作器和一个进度条。

public class TrayIconTest { public static void main(String[] args) throws AWTException { JFrame frame = new JFrame("TrayIconTest"); frame.setDefaultCloSEOperation(WindowConstants.EXIT_ON_CLOSE); Container contentPane = frame.getContentPane(); JProgressBar jProgressBar = new JProgressBar(); BoundedRangeModel boundedRangeModel = jProgressBar.getModel(); contentPane.add(jProgressBar); boundedRangeModel.setMinimum(0); boundedRangeModel.setMaximum(100); PopupMenu popup = new PopupMenu(); TrayIcon trayIcon = new TrayIcon(new BufferedImage(64,64,BufferedImage.TYPE_INT_RGB),"TEST"); // Create a popup menu components MenuItem aboutItem = new MenuItem("About"); popup.add(aboutItem); trayIcon.setPopupMenu(popup); SystemTray tray = SystemTray.getSystemTray(); tray.add(trayIcon); IndeterminateSwingWorker indeterminateSwingWorker = new IndeterminateSwingWorker(boundedRangeModel); indeterminateSwingWorker.execute(); frame.setSize(640,80); frame.setLocationRelativeto(null); frame.setVisible(true); } } class IndeterminateSwingWorker extends SwingWorker<Void,Integer> { private BoundedRangeModel boundedRangeModel; public IndeterminateSwingWorker(BoundedRangeModel boundedRangeModel) { this.boundedRangeModel = boundedRangeModel; } @Override protected Void doInBackground() throws Exception { int i = 0; long start = System.currentTimeMillis(); long runtime = TimeUnit.MILLISECONDS.convert(5,TimeUnit.MINUTES); while (true) { i++; i %= boundedRangeModel.getMaximum(); publish(i); Thread.sleep(20); long Now = System.currentTimeMillis(); if ((Now - start) > runtime) { break; } System.out.println("i = " + i); } return null; } @Override protected void process(List<Integer> chunks) { for (Integer chunk : chunks) { boundedRangeModel.setValue(chunk); } } }

如何重现

如何将另一个应用程序的窗口句柄最小化到系统托盘?

系统托盘上下文菜单空白

如何更改由Shell_NotifyIcon设置的systray图标文本样式

使用系统托盘图标创build一个后台进程

如何检查NotifyIcon是否隐藏

当您启动示例应用程序时,您将看到一个带有进度条的框架。 SwingWorker模拟进程动作。

SwingWorker发布进度值并将其打印到System.out 。

当我点击托盘图标('黑色')时,进度条冻结,popup菜单出现。 我可以看到SwingWorker仍然在后台运行,因为它将进度值输出到命令行。

调查

所以我使用jvisualvm来看看应用程序,它告诉我,只要popup窗口是可见的,事件分派器线程就非常忙碌。

我可以弄清楚看sun.awt.windows.WTrayIconPeer.showPopupMenu(int,int)是由sun.awt.windows.WTrayIconPeer.showPopupMenu(int,int)方法可见的。

方法使用EventQueue.invokelater提交可运行的事件到事件派发线程。 在这个可运行的方法中,调用sun.awt.windows.WPopupMenuPeer._show方法。 这种方法是native , 它似乎实现了一个繁忙的等待循环,以便事件调度线程完全被这个方法占用 。 因此,只要popup菜单是可见的,其他与UI相关的任务就不会被执行。

有没有人知道一个解决scheme,使TrayIconpopup窗口显示时保持事件调度线程响应?

正确的行为托盘图标点击?

如何确保我的启动程序在加载系统托盘后运行?

为什么系统托盘图标会清除先前显示的图标?

Windows任务栏(Windows 7?) – 如何在“控制面板”通知对话框中设置应用程序名称

如何从C#系统托盘应用程序作为线程运行C程序?

我现在使用jpopupmenu作为解决方法,但不能将jpopupmenu直接添加到TrayIcon 。

诀窍是写一个Mouselistner

public class jpopupmenuMouseAdapter extends MouseAdapter { private jpopupmenu popupMenu; public jpopupmenuMouseAdapter(jpopupmenu popupMenu) { this.popupMenu = popupMenu; } @Override public void mouseReleased(MouseEvent e) { maybeShowPopup(e); } @Override public void mousepressed(MouseEvent e) { maybeShowPopup(e); } private void maybeShowPopup(MouseEvent e) { if (e.isPopupTrigger()) { Dimension size = popupMenu.getPreferredSize(); popupMenu.setLocation(e.getX() - size.width,e.getY() - size.height); popupMenu.setInvoker(popupMenu); popupMenu.setVisible(true); } }

并将其连接到TrayIcon

TrayIcon trayIcon = ...; jpopupmenu popupMenu = ...; jpopupmenuMouseAdapter jpopupmenuMouseAdapter = new jpopupmenuMouseAdapter(popupMenu); trayIcon.addMouselistner(jpopupmenuMouseAdapter);

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐