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?

- 3,741
- 12
- 49
- 72

- 24,612
- 35
- 133
- 221
-
1Maybe you can start with [this](http://stackoverflow.com/questions/1882055/java-swing-change-background-color-on-mouse-over) – Jefferson Jan 17 '13 at 02:20
-
1Start by having a look at [How to use the System Tray](http://docs.oracle.com/javase/tutorial/uiswing/misc/systemtray.html) – MadProgrammer Jan 17 '13 at 02:20
-
1Is it specific about system tray? Or you just want to know about onMouseOver event? For system tray feature you can see http://docs.oracle.com/javase/tutorial/uiswing/misc/systemtray.html – Jon Kartago Lamida Jan 17 '13 at 02:20
-
@JonKartagoLamida Specific for system tray. – An SO User Jan 17 '13 at 02:20
-
Once you have had a look at the tutorials, I'd have a look at [JPopupMenu in TrayIcon](http://weblogs.java.net/blog/ixmal/archive/2006/05/using_jpopupmen.html) – MadProgrammer Jan 17 '13 at 02:23
-
@MadProgrammer working on that as well as not being able to play sound in a jar file – An SO User Jan 17 '13 at 02:24
-
1@LittleChild I was thinking more along the lines of once you've had a look at "How to use System Tray" tutorial, then look at the "JPopupMenu in TrayIcon" as it might be of interest – MadProgrammer Jan 17 '13 at 02:39
2 Answers
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...
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;
}
}

- 343,457
- 22
- 230
- 366
-
`JWindow` is basically like a `JPanel` that can be shown on the screen, correct ? – An SO User Jan 17 '13 at 08:54
-
No, not really. `JWindow` is more like an undecorated `JFrame` (`JFrame` extends from `JWindow`) – MadProgrammer Jan 17 '13 at 09:02
-
I knew the hierarchy, was just giving a simile :) If you are still in the mood for some more Java: http://stackoverflow.com/questions/14375338/cannot-play-embedded-sound-in-a-jar-file – An SO User Jan 17 '13 at 09:03
At first, I thought this would be fairly trivial - add a mouse listener to the TrayIcon using addMouseListener() and use the mouseEntered() and mouseExitedEvents():
icon.addMouseListener(new MouseAdapter()
{
@Override
public void mouseEntered(MouseEvent e)
{
System.out.println("Mouse over icon");
}
@Override
public void mouseExited(MouseEvent e)
{
System.out.println("Mouse leaving icon");
}
});
But, at least on the platform I tested with (Java 7u10 on Windows) this did not work - no events were generated when I hovered the mouse cursor over the tray icon. What did work was a MouseMotionListener
and the addMouseMotionListener
method:
icon.addMouseMotionListener(new MouseMotionAdapter()
{
@Override
public void mouseMoved(MouseEvent e)
{
System.out.println("Moving...");
}
});
Events are generated in mouseMoved()
only when the mouse is over the icon. With a bit of work, this could be used to display a JWindow
after a certain delay after first event is received to emulate tooltip time (you can get the platform's tooltip display time through something like ToolTipManager.sharedInstance().getInitialDelay()
.

- 22,460
- 3
- 73
- 80