Как перехватить trayicon.displayMessage () щелчок мышью по всплывающей подсказке - PullRequest
10 голосов
/ 11 декабря 2011

Привет, я пытаюсь показать более подробную информацию после того, как пользователь нажимает всплывающую подсказку с сообщением.

Однако я не могу найти способ захвата этого события.

Этоможно сделать?

Ответы [ 2 ]

11 голосов
/ 11 декабря 2011

1) Возможно прослушивание MouseClickEvents путем добавления ActionListener в TrayIcon, а затем прослушивание тела сообщения для 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() {
    }
}
2 голосов
/ 07 июня 2013

Несмотря на то, что эта тема не совсем новая, я решил поделиться своим решением, поскольку такого рода вещи не меняются.


Как использовать

Чтобы использовать этот код, просто создайте 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();

}
...