如何捕获trayicon.displayMessage()鼠标点击工具提示气球

嗨,我想在用户点击消息气球工具提示后显示更详细的信息。

但是,我找不到如何捕获该事件。

这可能吗?

1)可以通过将ActionListener添加到TrayIcon来监听MouseClickEvents,然后Message body侦听MouseClicked

2)(没有直接询问)但我不能给你一个答案,如果消息是通过关闭按钮关闭,消息以同样的方式离开屏幕,但没有捕获任何事件

3)看起来像这个Java TrayIcon消息关闭按钮应该只是一个解决方案,因为API没有实现另一种方法,

import java.awt.*; import java.awt.event.*; public class FullTray { private static class ShowMessageListener implements ActionListener { private TrayIcon trayIcon; private String title; private String message; private TrayIcon.MessageType messageType; ShowMessageListener(TrayIcon trayIcon, String title, String message, TrayIcon.MessageType messageType) { this.trayIcon = trayIcon; this.title = title; this.message = message; this.messageType = messageType; } public void actionPerformed(ActionEvent e) { trayIcon.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { System.out.println("Message Clicked"); } }); trayIcon.displayMessage(title, message, messageType); } } public static void main(String args[]) { Runnable runner = new Runnable() { public void run() { if (SystemTray.isSupported()) { final SystemTray tray = SystemTray.getSystemTray(); Image image = Toolkit.getDefaultToolkit().getImage("gifIcon.gif"); PopupMenu popup = new PopupMenu(); final TrayIcon trayIcon = new TrayIcon(image, "The Tip Text", popup); MenuItem item = new MenuItem("Error"); item.addActionListener(new ShowMessageListener(trayIcon, "Error Title", "Error", TrayIcon.MessageType.ERROR)); popup.add(item); item = new MenuItem("Warning"); item.addActionListener(new ShowMessageListener(trayIcon, "Warning Title", "Warning", TrayIcon.MessageType.WARNING)); popup.add(item); item = new MenuItem("Info"); item.addActionListener(new ShowMessageListener(trayIcon, "Info Title", "Info", TrayIcon.MessageType.INFO)); popup.add(item); item = new MenuItem("None"); item.addActionListener(new ShowMessageListener(trayIcon, "None Title", "None", TrayIcon.MessageType.NONE)); popup.add(item); item = new MenuItem("Close"); item.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { tray.remove(trayIcon); } }); popup.add(item); try { tray.add(trayIcon); } catch (AWTException e) { System.err.println("Can't add to tray"); } } else { System.err.println("Tray unavailable"); } } }; EventQueue.invokeLater(runner); } private FullTray() { } } 

虽然这个话题不是最近的,但我想我会分享我的解决方案,因为这种事情并没有真正改变。


如何使用

要使用此代码,只需创建1个公共类和2个公共接口。

现在创建一个CustomTrayIcon类的实例,并在初始化之后调用addToSystemTray()方法。

只要您想显示通知气泡,请调用showBubbleNotification(…)方法。

要删除此托盘图标,只需调用removeFromSystemTray()方法即可。


CustomTrayIcon

这个类是完成所有繁重工作的基础。

 package com.samples; import java.awt.AWTException; import java.awt.Image; import java.awt.PopupMenu; import java.awt.SystemTray; import java.awt.TrayIcon; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; /** * This class can be used to create an icon in the {@link SystemTray}, providing * the current operating system supports the {@link SystemTray}. 
*
* Userful Methods: *
    *
  • * Use the {@link CustomTrayIcon#addToSystemTray() addToSystemTray()} method to * add this {@link CustomTrayIcon} to the {@link SystemTray}.
    *
  • *
  • * Use the {@link CustomTrayIcon#removeFromSystemTray() removeFromSystemTray()} * method to remove this {@link CustomTrayIcon} from the {@link SystemTray}.
    *
  • *
  • * Use the * {@link CustomTrayIcon#showBubbleNotification(String, String, MessageType, CustomTrayIconNotificationBubbleClickEvent) * showBubbleNotification(String, String, MessageType, * CustomTrayIconNotificationBubbleClickEvent)} method to show a bubble notification to * the user.
    *
  • *
  • * Use the {@link CustomTrayIcon#setClickDetectionDelay_override(int) * setClickDetectionDelay_override(int)} method to override the default delay to * be used when detecting if a user performed a single/double/triple click.
  • *
* * @author Matthew Weiler * */ public abstract class CustomTrayIcon extends TrayIcon implements CustomTrayIconMouseInterface { /* PRIVATE CONSTANTS */ /** * This will be used as the millisecond delay between clicks to detect * single or double clicks.
*
* Default Value: 300 * */ private static final int DEFAULT_CLICK_DETECTION_DELAY = 300; /** * This will be used to ensure that we can synchronize the click counter * changes. * */ private static final Object clickLock = new Object(); /* PRIVATE VARIABLES */ /** * This will store the override value to be used in-place of the * {@link CustomTrayIcon#DEFAULT_CLICK_DETECTION_DELAY CLICK_DETECTION_DELAY} * default value. * * @see CustomTrayIcon#DEFAULT_CLICK_DETECTION_DELAY * */ private int clickDetectionDelay_override = -1; /** * This will store the {@link CustomTrayIconNotificationBubbleClickEvent} which * should be executed the next time that an {@link ActionEvent} is fired by * the user clicking a notification bubble. * */ private CustomTrayIconNotificationBubbleClickEvent newBubbleAction = null; /** * This will be used to keep track of which click was responsible for the * current click timer. * */ private long clickOwnerIndex = 0L; /** * This will be used to keep track of how many clicks occurred in the * current click detection cycle. * */ private int clickCounter = 0; /* CONSTRUCTORS */ /** * This will create a new instance of a {@link CustomTrayIcon}. * * @param image * The {@link Image} to display as the icon in the notification * tray. * */ public CustomTrayIcon(final Image image) { super(image); this.postCreateTasks(); } /** * This will create a new instance of a {@link CustomTrayIcon}. * * @param image * The {@link Image} to display as the icon in the notification * tray. * @param tooltip * The string to be used as tooltip text; if the value is null no * tooltip is shown. * */ public CustomTrayIcon(final Image image, final String tooltip) { super(image, tooltip); this.postCreateTasks(); } /** * This will create a new {@link CustomTrayIcon}.
* The {@link CustomTrayIcon} * */ public CustomTrayIcon(final Image image, final String tooltip, final PopupMenu popup) { super(image, tooltip, popup); this.postCreateTasks(); } /* PUBLIC METHODS */ /** * This will determine if the current operating system supports * {@link SystemTray}. * * @see SystemTray#isSupported() * * @return
true if the current operating system supports * {@link SystemTray}; false otherwise. * */ public static boolean isSystemTraySupported() { return SystemTray.isSupported(); } /** * This method will add this {@link CustomTrayIcon} to {@link SystemTray} .
*
* this method may return false if the current operating * system does not have or support a {@link SystemTray} * * @return true if this {@link CustomTrayIcon} was added; * false otherwise. * */ public boolean addToSystemTray() { // Ensure that the current operating system supports // the SystemTray. if (CustomTrayIcon.isSystemTraySupported()) { try { // Add this CustomTrayIcon to the SystemTray. SystemTray.getSystemTray().add(this); return true; } catch (AWTException e) { // ignore } } return false; } /** * This method will remove this {@link CustomTrayIcon} from the * {@link SystemTray}. * */ public void removeFromSystemTray() { SystemTray.getSystemTray().remove(this); } @Override public void displayMessage(final String caption, final String text, final MessageType messageType) { this.newBubbleAction = null; super.displayMessage(caption, text, messageType); } /** * This method will show a bubble notification near the * {@link CustomTrayIcon}. * * @see TrayIcon#displayMessage(String, String, MessageType) * * @param title * The title to be displayed in the bubble notification. * @param message * The message to be displayed in the bubble notification. * @param messageType * The type of {@link MessageType} which will denote the style of * the bubble notification. * @param actionOnClick * The {@link CustomTrayIconNotificationBubbleClickEvent} which should be * fired when the user clicks the bubble notification. * * @throws NullPointerException * If both caption and text are null. * */ public void displayMessage(final String title, final String message, final MessageType messageType, final CustomTrayIconNotificationBubbleClickEvent actionOnClick) { this.showBubbleNotification(title, message, messageType, actionOnClick); } /** * This method will show a bubble notification near the * {@link CustomTrayIcon}. * * @see TrayIcon#displayMessage(String, String, MessageType) * * @param title * The title to be displayed in the bubble notification. * @param message * The message to be displayed in the bubble notification. * @param messageType * The type of {@link MessageType} which will denote the style of * the bubble notification. * * @throws NullPointerException * If both caption and text are null. * */ public void showBubbleNotification(final String title, final String message, final MessageType messageType) { this.showBubbleNotification(title, message, messageType, null); } /** * This method will show a bubble notification near the * {@link CustomTrayIcon}. * * @see TrayIcon#displayMessage(String, String, MessageType) * * @param title * The title to be displayed in the bubble notification. * @param message * The message to be displayed in the bubble notification. * @param messageType * The type of {@link MessageType} which will denote the style of * the bubble notification. * @param actionOnClick * The {@link CustomTrayIconNotificationBubbleClickEvent} which should be * fired when the user clicks the bubble notification. * * @throws NullPointerException * If both caption and text are null. * */ public void showBubbleNotification(final String title, final String message, final MessageType messageType, final CustomTrayIconNotificationBubbleClickEvent actionOnClick) { this.newBubbleAction = actionOnClick; super.displayMessage(title, message, messageType); } /* GETTERS & SETTERS */ /** * This will get the override value to be used in-place of the * {@link CustomTrayIcon#DEFAULT_CLICK_DETECTION_DELAY CLICK_DETECTION_DELAY} * default value. * * @see CustomTrayIcon#DEFAULT_CLICK_DETECTION_DELAY * * @return The override value to be used in-place of the * {@link CustomTrayIcon#DEFAULT_CLICK_DETECTION_DELAY * CLICK_DETECTION_DELAY} default value. * */ public int getClickDetectionDelay_override() { return this.clickDetectionDelay_override; } /** * This will set the override value to be used in-place of the * {@link CustomTrayIcon#DEFAULT_CLICK_DETECTION_DELAY CLICK_DETECTION_DELAY} * default value. * * @see CustomTrayIcon#DEFAULT_CLICK_DETECTION_DELAY * * @param clickDetectionDelay_override * The override value to be used in-place of the * {@link CustomTrayIcon#DEFAULT_CLICK_DETECTION_DELAY * CLICK_DETECTION_DELAY} default value. * */ public void setClickDetectionDelay_override(final int clickDetectionDelay_override) { this.clickDetectionDelay_override = clickDetectionDelay_override; } /* PRIVATE METHODS */ /** * This method will return the delay to have between each click when * determining if the user performed a single/double/triple click. * * @return The delay to have between each click when determining if the user * performed a single/double/triple click. * */ private int getClickDetectionDelay() { if (this.clickDetectionDelay_override > 0) { return this.clickDetectionDelay_override; } return CustomTrayIcon.DEFAULT_CLICK_DETECTION_DELAY; } /** * This method will be executed as the constructors last task.
*
* this method will set some attributes on this {@link CustomTrayIcon} and * apply the appropriate listeners * */ private void postCreateTasks() { this.setImageAutoSize(true); this.applyCustomListeners(); } /** * This will apply the various listeners to this {@link CustomTrayIcon} * object. * */ private void applyCustomListeners() { // Add an ActionListener which will fire when the user // clicks a bubble notification. this.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { if (CustomTrayIcon.this.newBubbleAction != null) { CustomTrayIcon.this.newBubbleAction.button1_click(); CustomTrayIcon.this.newBubbleAction = null; } } }); // Add a MouseListener on this CustomTrayIcon which will // fire when the user interacts with this CustomTrayIcon // using their mouse. this.addMouseListener(new MouseListener() { @Override public void mouseReleased(MouseEvent arg0) { // NOT SUPPORTED BY TrayIcon } @Override public void mousePressed(MouseEvent arg0) { // NOT SUPPORTED BY TrayIcon } @Override public void mouseExited(MouseEvent arg0) { } @Override public void mouseEntered(MouseEvent arg0) { } @Override public void mouseClicked(MouseEvent arg0) { // Clear the bubble notification action as any open // bubbles should be popped/closed when this interaction // occurs. CustomTrayIcon.this.newBubbleAction = null; // If this MouseEvent was triggered by mouse button 1 // being clicked... then continue. if (arg0.getButton() == MouseEvent.BUTTON1) { long tmp_clickOwnerIndex = 0L; // Ensure that only one thread can modify the click owner index // at any given time. synchronized (CustomTrayIcon.clickLock) { // Increase the click owner index so that only the very // last click can fire an event. CustomTrayIcon.this.clickOwnerIndex++; // Store the current value of the click owner index tmp_clickOwnerIndex = CustomTrayIcon.this.clickOwnerIndex; } // Extract the click owner index, which was obtained in a // thread-safe way, into a final variable so we can access it // below. final long tmp_clickOwnerIndex_final = tmp_clickOwnerIndex; // Launch a new Thread which will sleep for a pre-determined // period of time to catch the delay of a double/triple click. (new Thread() { int tmp_clickCounter = 0; public void run() { // Ensure that only one thread can modify the click // counter at any given time. synchronized (CustomTrayIcon.clickLock) { // Increase the number of active clicks that occurred // during the current detection cycle. CustomTrayIcon.this.clickCounter++; // Extract the total number of active clicks that occurred // during the current detection cycle up to this point. tmp_clickCounter = CustomTrayIcon.this.clickCounter; } try { // Sleep for the pre-determined multiple click detection // time. // This ensures that we give the use enough time to // actually perform multiple clicks. Thread.sleep(CustomTrayIcon.this.getClickDetectionDelay()); } catch (InterruptedException e) { // ignore } // Ensure that only one thread can modify the click owner index // at any given time. synchronized (CustomTrayIcon.clickLock) { // If this click was the last click since the appropriate // delay, then it's clear that this click should be // processed. if (CustomTrayIcon.this.clickOwnerIndex == tmp_clickOwnerIndex_final) { // If only one click occurred during the allocated delayed // time, then fire a button 1 click. if (tmp_clickCounter == 1) { CustomTrayIcon.this.button1_click(); } // If two clicks occurred during the allocated delayed // time, then fire a button 2 click. else if (tmp_clickCounter == 2) { CustomTrayIcon.this.button1_doubleClick(); } // If three clicks occurred during the allocated delayed // time, then fire a button 3 click. else if (tmp_clickCounter == 3) { CustomTrayIcon.this.button1_tripleClick(); } } // Decrease the click owner index which will reset the // click stack. CustomTrayIcon.this.clickCounter--; } } }).start(); } // If this MouseEvent was triggered by mouse button 2 // being clicked... then continue. else if (arg0.getButton() == MouseEvent.BUTTON2) { // Ensure that only one thread can modify the click owner index // at any given time. synchronized (CustomTrayIcon.clickLock) { // Increase the click owner index so that only the very // last click can fire an event. CustomTrayIcon.this.clickOwnerIndex++; } CustomTrayIcon.this.button2_click(); } // If this MouseEvent was triggered by mouse button 3 // being clicked... then continue. else if (arg0.getButton() == MouseEvent.BUTTON3) { // Ensure that only one thread can modify the click owner index // at any given time. synchronized (CustomTrayIcon.clickLock) { // Increase the click owner index so that only the very // last click can fire an event. CustomTrayIcon.this.clickOwnerIndex++; } CustomTrayIcon.this.button3_click(); } } }); } }

CustomTrayIconMouseInterface

此接口用于通过鼠标外部化各种用户交互。

 package com.samples; import javax.swing.Popup; /** * This interface contains several methods which can be fired when a user * interacts with the {@link CustomTrayIcon} using their mouse. * * @author Matthew Weiler * */ public interface CustomTrayIconMouseInterface { /** * This method will be fired when the user clicks, with mouse button 1, this * {@link CustomTrayIcon}. * */ public void button1_click(); /** * This method will be fired when the user double-clicks, with mouse button * 1, this {@link CustomTrayIcon}. * */ public void button1_doubleClick(); /** * This method will be fired when the user triple-clicks, with mouse button * 1, this {@link CustomTrayIcon}. * */ public void button1_tripleClick(); /** * This method will be fired when the user clicks, with mouse button 2, this * {@link CustomTrayIcon}. * */ public void button2_click(); /** * This method will be fired when the user clicks, with mouse button 3, this * {@link CustomTrayIcon}. 
*
* if a {@link Popup} menu is assigned to this {@link CustomTrayIcon}, it * will still popup regardless of any actions taken by this method * */ public void button3_click(); }

CustomTrayIconNotificationBubbleClickEvent

此界面用于外部化与通知气泡的交互。

 package com.samples; /** * This interface contains several methods which can be fired when a user * interacts with a bubble notification using their mouse. * * @author Matthew Weiler * */ public interface CustomTrayIconNotificationBubbleClickEvent { /** * This method will be fired when the user clicks, with mouse button 1, this * bubble notification. * */ public void button1_click(); }