So you may have wondered “How do I get a nifty little icon in the system tray for my Java App?” and after 20 minutes of banging your head against the wall you got dizzy, fell down, and probably passed out to only wake up and forget what you were doing. Then you go on your merry way to play some Nintendo Wii Fit. Yeah right! We all know you got up and remember exactly what you wanted but didn’t know how to do it. So I am here to show you. Starting in Java 6 SE they introduced the system tray icon capabilities. Lets give them a whirl and build a small app on this entry of the Programming Underground!
In Java SDK 6 (I am using SDK 6 update 7) they introduced two new objects. One is TrayIcon which is a class for handling the actual icon and all its abilities like showing menus, listening to events and handling nifty tooltips. Then they introduced the SystemTray class which is a static class (meaning you don’t initiate an instance of the class, you can just call its methods like “add” using the class name) which handles the actual system tray.
The system tray can be the windows taskbar status area, it could be the notification area in Gnome, or even KDE’s system tray to name a few. These two objects work the same despite the platform. But before handling anything with the system tray, we need to make sure that we call the isSupported method of the SystemTray object to make sure that the current system does have a system tray and it does support accessing it before we try to use it.
So below is a small little project I put together using little bits here and there to show you how this all works. We created a project which extends from a Java swing JFrame object. We make this frame about 300 x 300 pixels in size and give it the standard features using our main method. The frame itself really doesn’t display anything and is only used to show you that you could build your app like normal with buttons and controls and use this icon in the system tray to interact with it.
You will also notice that we create a TrayIcon variable at class level which will hold a reference to the actual trayIcon. We didn’t have to specify it at this level and could have kept it local, but you may want multiple functions having access to it from time to time and maybe even change the icon as status in the application changes (using the setImage method).
// Import our swing components (for the JFrame) // Import our awt controls for things like the popup menu and image handling // Import java.awt.event for our listeners. import javax.swing.*; import java.awt.*; import java.awt.event.*; // Create a class that extends from swing JFrame public class SysTrayExample extends JFrame { // Class level variable to support our tray icon private TrayIcon trayIcon; // Main.. which creates an instance of our class, sets its caption, size, and shows it. public static void main(String args[]) { SysTrayExample f = new SysTrayExample(); f.setTitle("System Tray Example"); f.setSize(300,300); f.setDefaultCloseOperation(EXIT_ON_CLOSE); f.setVisible(true); } // Constructor. When we create the class in main, this function is called first thing. public SysTrayExample() { // Check to make sure the system does have a system tray we can access if (SystemTray.isSupported()) { // Fabulous, it supports a system tray. Set a variable to it so we can manipulate the tray using the variable of type // SystemTray. We will set the TrayIcon up and then add it to the tray using this variable. SystemTray tray = SystemTray.getSystemTray(); // Load an image from our c:\ drive and we are going to use this in the trayIcon Image image = Toolkit.getDefaultToolkit().getImage("c:\\xscope.gif"); // Here are our listeners. One listens for the popup menu "Close" command and terminates the program. // This will be attached to the popup menu item "close" ActionListener exitListener = new ActionListener() { public void actionPerformed(ActionEvent e) { System.exit(0); } }; // This message appears when an event has been detected. ActionListener actionListener = new ActionListener() { public void actionPerformed(ActionEvent e) { trayIcon.displayMessage("Event Performed", "An Action Event Has Been Performed!", TrayIcon.MessageType.INFO); } }; // Next we setup our popup menu. We then add one item to the menu called "close" to close our program. PopupMenu popup = new PopupMenu(); MenuItem defaultItem = new MenuItem("Close"); // Add our ActionListener called "exitlistener" to the popup menu item. defaultItem.addActionListener(exitListener); // Add the menu item finally to the popup menu. popup.add(defaultItem); // Now configure our tray icon and attach our actionListener to it to listen for actionPeformed events. trayIcon = new TrayIcon(image, "Here is our tray tool tip", popup); trayIcon.setImageAutoSize(true); trayIcon.addActionListener(actionListener); // Lastly, add the icon to the tray variable we defined above. // Since this can throw an error, lets trap the error and display a message if the add failed. try { tray.add(trayIcon); } catch (AWTException e) { System.err.println("Problem with adding icon to tray."); } } else { // We reach this error if the system simply won't let us access the tray or doesn't have one. System.err.println("This system does not support a System Tray being accessed by Java"); } } }
When this class is instantiated, it calls its constructor which does many things. It first checks to make sure that we can actually get at a SystemTray. This is where we use the isSupported method. Next we get the system tray object and an image we will use for the icon in the tray. After that we setup some event listeners where we will attach one to the trayIcon (to listen for events like a double click) and launch things like the tooltip and the other event will be attached to our context menu (which will appear when we right click the icon in the tray).
The next thing we do is create the popupmenu object, throw on a menuItem and call it “Close.” This is followed by attaching our event listener to the popup menu item. Now whenever someone selects the “Close” menu item, it will launch the listener called “exitListener” and terminate the program.
After all this we finally set the TrayIcon up with our image, tooltip text, and lastly the popup menu. We attach the actionlistener to it for the tooltip display and the very last thing we do, add the TrayIcon object to the SystemTray object using its static method “Add”.
So if you are following along in the code, with the in code comments, you can quickly see how this plays out. We check to see if we have a system tray, get the image for our TrayIcon, setup our application as normal, create a popup menu, attach events to the icon as well as the popup menu, setup the TrayIcon and finally add it to the SystemTray object.
The results of the different actions are shown below. The first one is what happens when you double click the icon. This triggers our actionListener to display the popup.
This second one is what happens when you right click the icon, which triggers the popup menu we attached to the icon. Actually clicking “Close” will kick off the exitListener we attached and terminate the program.
That is all there is to it! Feel free to take the code and edit it as you see fit. Play around with the bits and pieces and don’t forget to change the path of the image icon to an image you actually have on your computer. Here I am pulling a simple 16 x 16 gif file from my c:\ drive.
Thanks for reading and remember what Woodsy Owl said… “Give a hoot, don’t pollute your system tray!” Ok maybe he didn’t say that, but he would have if he knew Java. 🙂