嗨,我想在用户点击消息气球工具提示后显示更详细的信息。
但是,我找不到如何捕获该事件。
这可能吗?
答案 0 :(得分:11)
1)可以通过将ActionListener添加到TrayIcon来监听MouseClickEvents,然后将Message body侦听为MouseClicked
2)(没有直接询问)但是如果通过关闭按钮关闭消息,我就不能给你一个答案,而且消息以同样的方式离开屏幕,但没有捕获任何事件
3)看起来这个Java TrayIcon message close button应该只是一个解决方案,因为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)
即使这个主题不是最近的,我想我会分享我的解决方案,因为这种事情并没有真正改变。
如何使用
要使用此代码,只需创建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}. <br />
* <br />
* <b><u>Userful Methods</u>:</b>
* <ul>
* <li>
* Use the {@link CustomTrayIcon#addToSystemTray() addToSystemTray()} method to
* add this {@link CustomTrayIcon} to the {@link SystemTray}. <br />
* </li>
* <li>
* Use the {@link CustomTrayIcon#removeFromSystemTray() removeFromSystemTray()}
* method to remove this {@link CustomTrayIcon} from the {@link SystemTray}. <br />
* </li>
* <li>
* Use the
* {@link CustomTrayIcon#showBubbleNotification(String, String, MessageType, CustomTrayIconNotificationBubbleClickEvent)
* showBubbleNotification(String, String, MessageType,
* CustomTrayIconNotificationBubbleClickEvent)} method to show a bubble notification to
* the user. <br />
* </li>
* <li>
* 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.</li>
* </ul>
*
* @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. <br />
* <br />
* <b><u>Default Value</u>:</b> 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}. <br />
* 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 <code>true</code> if the current operating system supports
* {@link SystemTray}; <code>false</code> otherwise.
* */
public static boolean isSystemTraySupported()
{
return SystemTray.isSupported();
}
/**
* This method will add this {@link CustomTrayIcon} to {@link SystemTray} . <br />
* <br />
* <i>this method may return <code>false</code> if the current operating
* system does not have or support a {@link SystemTray}</i>
*
* @return <code>true</code> if this {@link CustomTrayIcon} was added;
* <code>false</code> 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 <code>null</code>.
* */
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 <code>null</code>.
* */
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 <code>null</code>.
* */
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. <br />
* <br />
* <i>this method will set some attributes on this {@link CustomTrayIcon} and
* apply the appropriate listeners</i>
* */
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}. <br />
* <br />
* <i>if a {@link Popup} menu is assigned to this {@link CustomTrayIcon}, it
* will still popup regardless of any actions taken by this method</i>
* */
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();
}