Search code examples
javaswingmouseeventmouseoversystem-tray

How do I add things to the system tray and add mouseOver() functionality?


enter image description here

Sorry if the title was vague but this is what I am trying to implement.
This is Battery Care software iconified / minimized. When you mouse over the icon, you get the window you see in the picture.
How can that be implemented in Java?


Solution

  • enter image description here

    This uses a JPopupMenu to display information on a click, not the most recommended approach, as it's difficult to layout other components...but you could just as easily use a JWindow instead...

    public class SystemTrayTest {
    
      public static void main(String[] args) {
        if (SystemTray.isSupported()) {
    
          EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
              try {
                UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
              } catch (Exception ex) {
              }
              try {
                final JPopupMenu popup = new JPopupMenu();
                popup.add(new JLabel("Charging (45%)", JLabel.CENTER));
    
                popup.add(new JLabel("Charging", new ImageIcon(ImageIO.read(SystemTrayTest.class.getResource("/battery_connection.png"))), JLabel.LEFT));
                popup.add(new JLabel("Power Saver", new ImageIcon(ImageIO.read(SystemTrayTest.class.getResource("/flash_yellow.png"))), JLabel.LEFT));
    
                popup.add(new JSeparator());
    
                JMenuItem exitMI = new JMenuItem("Exit");
                exitMI.addActionListener(new ActionListener() {
                  @Override
                  public void actionPerformed(ActionEvent e) {
                    System.exit(0);
                  }
                });
                popup.add(exitMI);
    
                TrayIcon trayIcon = new TrayIcon(ImageIO.read(SystemTrayTest.class.getResource("/battery_green.png")), "Feel the power");
                trayIcon.addMouseListener(new MouseAdapter() {
                  @Override
                  public void mouseClicked(MouseEvent e) {
                    popup.setLocation(e.getX(), e.getY());
                    popup.setInvoker(popup);
                    popup.setVisible(true);
                  }
                });
                SystemTray.getSystemTray().add(trayIcon);
              } catch (Exception ex) {
                ex.printStackTrace();
                System.exit(0);
              }
    
            }
          });
        }
    
      }
    }
    

    Updated with mouse over support

    Cause I can't resist playing...

    enter image description here

    public class SystemTrayTest {
    
      public static void main(String[] args) {
        new SystemTrayTest();
      }
    
      public SystemTrayTest() {
        if (SystemTray.isSupported()) {
    
          EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
              try {
                UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
              } catch (Exception ex) {
              }
              try {
                TrayIcon trayIcon = new TrayIcon(ImageIO.read(SystemTrayTest.class.getResource("/battery_green.png")), "Feel the power");
                MouseHandler mouseHandler = new MouseHandler();
                trayIcon.addMouseMotionListener(mouseHandler);
                trayIcon.addMouseListener(mouseHandler);
                SystemTray.getSystemTray().add(trayIcon);
              } catch (Exception ex) {
                ex.printStackTrace();
                System.exit(0);
              }
            }
          });
        }
      }
    
      public class MouseHandler extends MouseAdapter {
    
        private Timer popupTimer;
        private JWindow popup;
        private Point point;
    
        public MouseHandler() {
          popup = new JWindow();
          ((JComponent)popup.getContentPane()).setBorder(new LineBorder(Color.LIGHT_GRAY));
          popup.setLayout(new GridLayout(0, 1));
          popup.add(new JLabel("Charging (45%)", JLabel.CENTER));
    
          try {
            popup.add(new JLabel("Charging", new ImageIcon(ImageIO.read(getClass().getResource("/battery_connection.png"))), JLabel.LEFT));
            popup.add(new JLabel("Power Saver", new ImageIcon(ImageIO.read(getClass().getResource("/flash_yellow.png"))), JLabel.LEFT));
          } catch (IOException exp) {
            exp.printStackTrace();
          }
          popup.pack();
    
          popupTimer = new Timer(250, new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
              if (point != null) {
                System.out.println(point);
                Rectangle bounds = getScreenViewableBounds(point);
                int x = point.x;
                int y = point.y;
                if (y < bounds.y) {
                  y = bounds.y;
                } else if (y > bounds.y + bounds.height) {
                  y = bounds.y + bounds.height;
                }
                if (x < bounds.x) {
                  x = bounds.x;
                } else if (x > bounds.x + bounds.width) {
                  x = bounds.x + bounds.width;
                }
    
                if (x + popup.getWidth() > bounds.x + bounds.width) {
                  x = (bounds.x + bounds.width) - popup.getWidth();
                }
                if (y + popup.getWidth() > bounds.y + bounds.height) {
                  y = (bounds.y + bounds.height) - popup.getHeight();
                }
                popup.setLocation(x, y);
                popup.setVisible(true);
              }
            }
          });
          popupTimer.setRepeats(false);
    
        }
    
        @Override
        public void mouseExited(MouseEvent e) {
          System.out.println("Stop");
          point = null;
          popupTimer.stop();
          popup.setVisible(false);
        }
    
        @Override
        public void mouseMoved(MouseEvent e) {
          popupTimer.restart();
          point = e.getPoint();
        }
    
        @Override
        public void mouseClicked(MouseEvent e) {
          System.exit(0);
        }
      }
    
      public static GraphicsDevice getGraphicsDeviceAt(Point pos) {
    
        GraphicsDevice device = null;
    
        GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
        GraphicsDevice lstGDs[] = ge.getScreenDevices();
    
        ArrayList<GraphicsDevice> lstDevices = new ArrayList<GraphicsDevice>(lstGDs.length);
    
        for (GraphicsDevice gd : lstGDs) {
    
          GraphicsConfiguration gc = gd.getDefaultConfiguration();
          Rectangle screenBounds = gc.getBounds();
    
          if (screenBounds.contains(pos)) {
    
            lstDevices.add(gd);
    
          }
    
        }
    
        if (lstDevices.size() == 1) {
    
          device = lstDevices.get(0);
    
        }
    
        return device;
    
      }
    
      public static Rectangle getScreenViewableBounds(Point p) {
    
        return getScreenViewableBounds(getGraphicsDeviceAt(p));
    
      }
    
      public static Rectangle getScreenViewableBounds(GraphicsDevice gd) {
    
        Rectangle bounds = new Rectangle(0, 0, 0, 0);
    
        if (gd != null) {
    
          GraphicsConfiguration gc = gd.getDefaultConfiguration();
          bounds = gc.getBounds();
    
          Insets insets = Toolkit.getDefaultToolkit().getScreenInsets(gc);
    
          bounds.x += insets.left;
          bounds.y += insets.top;
          bounds.width -= (insets.left + insets.right);
          bounds.height -= (insets.top + insets.bottom);
    
        }
    
        return bounds;
    
      }
    }