Dustin Fain
Dustin Fain

Reputation: 120

How to spring JFrame from System Tray in Java

I'm able to create a system tray application in Java, but I'm having trouble with positioning. The program will simply need to handle a few inputs/outputs, so I would like it to be easily accessible.

My question is, when I click the system tray icon for my application how can I set it's position elegantly above the system tray? The requirements being that it does this regardless of display settings (resolution, multi monitors, etc) and Taskbar location. Is there a way to tell it to open near the tray, rather than positioning it at all?

I want it to do exactly what the "Network" settings button does in Windows. Similar to the following:

Network System Tray Image

Is this possible in Java?

Upvotes: 2

Views: 2460

Answers (2)

MadProgrammer
MadProgrammer

Reputation: 347204

As Vulcan has pointed out, yes it's possible.

Also, it's very possible to take into consideration where to place the popup (with relevance to the location where the task icon is)

Show me the popup

public class TestTrayIcon {

    protected static final PopupFrame POPUP_FRAME = new PopupFrame();

    public static void main(String[] args) {

        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {

                try {
                    TrayIcon trayIcon = new TrayIcon(ImageIO.read(new File("D:/DevWork/common/icons/iconex_v_bundle_png/iconexperience/v_collections_png/basic_foundation/16x16/plain/about.png")));
                    trayIcon.addMouseListener(new MouseAdapter() {
                        @Override
                        public void mouseClicked(MouseEvent e) {

                            Point pos = e.getLocationOnScreen();
                            Rectangle screen = getScreenBoundsAt(pos);

                            if (pos.x + POPUP_FRAME.getWidth() > screen.x + screen.width) {
                                pos.x = screen.x + screen.width - POPUP_FRAME.getWidth();
                            }
                            if (pos.x < screen.x) {
                                pos.x = screen.x;
                            }

                            if (pos.y + POPUP_FRAME.getHeight() > screen.y + screen.height) {
                                pos.y = screen.y + screen.height - POPUP_FRAME.getHeight();
                            }
                            if (pos.y < screen.y) {
                                pos.y = screen.y;
                            }

                            POPUP_FRAME.setLocation(pos);
                            POPUP_FRAME.setVisible(true);

                        }
                    });
                    SystemTray.getSystemTray().add(trayIcon);
                } catch (Exception ex) {
                    ex.printStackTrace();
                }
            }
        });
    }

    public static class PopupFrame extends JFrame {

        public PopupFrame() throws HeadlessException {
            setLayout(new BorderLayout());
            add(new JLabel("Hello world"));
            pack();
        }
    }

    public static Rectangle getScreenBoundsAt(Point pos) {
        GraphicsDevice gd = getGraphicsDeviceAt(pos);
        Rectangle bounds = null;

        if (gd != null) {
            bounds = gd.getDefaultConfiguration().getBounds();
            Insets insets = Toolkit.getDefaultToolkit().getScreenInsets(gd.getDefaultConfiguration());

            bounds.x += insets.left;
            bounds.y += insets.top;
            bounds.width -= (insets.left + insets.right);
            bounds.height -= (insets.top + insets.bottom);
        }
        return bounds;
    }

    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;
    }
}

Upvotes: 9

FThompson
FThompson

Reputation: 28687

Yes, it is possible.

To set a window's location relative to the lower right corner of the screen, you can get the graphic environment's maximum window bounds and then perform simple math.

Rectangle screen = GraphicsEnvironment.getLocalGraphicsEnvironment()
        .getMaximumWindowBounds();
String os = System.getProperty("os.name");
if (os.contains("Windows")) {
    setLocation(screen.width - windowSize.width - 6, screen.height - windowSize.height - 6);
} else if (os.contains("Mac")) {
    setLocation(screen.width - windowSize.width + 6, 6);
}

The - 6 on both width and height accounts for the small gap between the window and the taskbar, and is easily customizable.

However, with this approach note that Windows taskbars located on the top or left side will still have a taskbar-sized gap on the right/bottom side of the window. I don't believe it is possible to find the taskbar orientation from the Java API alone.

Upvotes: 5

Related Questions