Build “Win-tuitive” Java Applications

Build “Win-tuitive” Java Applications

he ability to run Java applications on Windows is a clear demonstration of the language’s interoperability, but it also has its drawbacks from the user’s perspective. Since most Windows users regularly employ executable (.exe) files in their applications, they are not accustomed to—nor particularly fond of—using the bat files in Java applications. Besides, .bat files are ugly—they don’t even have their own icons like .exe files do. On top of that, Java applications on Windows don’t have access to the tray bar and users can’t start them as Windows Services.

Of course, a Java developer can use JNI to provide access to the tray bar, but he or she would have to write C code every time such a feature is required. Wouldn’t solving the problem once for all Java applications be better? As for the Windows Service shortcoming, a general service that starts or stops the Java application would solve that. However, this is not the best solution either. Because the service and the Java application each has its own security privileges, a simple logoff could destroy the application while the service continues to work.

This article introduces J2Exe, a free tool for noncommercial use that offers a solution for the drawbacks associated with Java applications on Windows. By using J2Exe, the Java developer can:

  • Make an .exe file (with its own icon) that will start his or her main class.
  • Enable use of the Windows tray bar and minimize the Java application.
  • Set the tray menu to receive events back in Java code.
  • Make the Java application a Windows Service.

How’s It Do That?
Under the hood, the J2Exe tool contains four modules:

  • J2Exe
  • J2TrayExe
  • J2WinService
  • J2TrayWinService

Each one is independent of the others. The J2Exe module makes standard .exe files, while the others make .exe files that either operate with the tray bar or act as Window Services. Download J2Exe and its accompanying example to follow along with this tutorial, which demonstrates how to use the tool.

Exercise 1: Develop a Simple Java Application with Its Own .exe
As an example for using J2Exe, take the following steps to write a simple application called MyServer that shows a mainframe with text.

  1. Create a directory called “c:J2ExeDemo”.
  2. Either open the downloaded example or just copy and paste the following code (MyServer application) for the Java file:
    package server;import java.awt.*;import java.awt.event.*;import javax.swing.*;public class MyServer {  public static void main(String[] args) {    JFrame frame = new JFrame();    frame.addWindowListener(new WindowAdapter() {      public void windowClosing(WindowEvent e) {System.exit(0);}    });        String message = "Ready!";    if (args.length > 0) message = args[0];     JLabel label = new JLabel(message, SwingConstants.CENTER);    frame.getContentPane().add(label, BorderLayout.CENTER);        Dimension scr = Toolkit.getDefaultToolkit().getScreenSize();    Dimension frm = new Dimension(200, 100);    int x = (scr.width - frm.width )/2;    int y = (scr.height - frm.height)/2;        frame.setSize(frm);    frame.setLocation(x, y);    frame.setTitle("MyServer");    frame.setVisible(true);  }}

    This is a simple application that shows a mainframe with text. It takes the text from the first program parameter. If such a parameter doesn’t exist, the default text is “Ready!”.

  3. Save the above Java file as “”.
  4. Open the command prompt in this directory and compile the file by typing: “javac”.

Now your application is ready. You can write the starting script, “MyServer.bat”:

cd ..injava -classpath . server.MyServercd ..lib

Save the .bat file as “c:J2ExeDemoinMyServer.bat”. You can click on it to see whether it works properly. The directory structure of the MyServer project should look like Figure 1.

Figure 1: Directory Structure of the MyServer Project

Now you are ready to start using J2Exe. Figure 2 shows the default “Input” options.

Figure 2: MyServer Project Input Options

First, pay attention to your startup script, which has four main components:

  • The Virtual Machine arguments (e.g., classpath, etc.)
  • The main class name (server.MyServer)
  • The program parameters (parameter1, parameter2)
  • The working directory (c:J2ExeDemolib)

You should enter the same information in the “Input” dialog’s text fields. The “Java Parameters” are Virtual Machine arguments, and the “Application parameters” are actually program parameters. The rest of the fields have the same designation as the startup script.

Pay particular attention to the working directory. Very often it is set with a relative path because users install their applications in different places. With this in mind, use the reserved word “%APP_HOME%” instead of an absolute path. “%APP_HOME%” represents the location from where the generated .exe file launches. In this case, “%APP_HOME%” is the same as “c:J2ExeDemoin”. In the starting script, the working directory is “c:J2ExeDemolib”. Therefore, you can specify “%APP_HOME%/…/lib” as a working directory, which is the same as “c:J2ExeDemolib”.

You are almost ready to produce your .exe file. Go to “Output” options (see Figure 3), and choose one of the three possible .exe file types: “JDK with Console”, “JDK with Managed Console”, or “JDK without Console”.

Figure 3: MyServer Project Output Options

“JDK with Console” is like starting with “java”, and “JDK without Console” is like working with “javaw”. The other file type, “JDK with Managed Console” (invented by Yours Truly), is also like starting with “javaw” but with a big difference—it enables you to show or hide the application console whenever you want to (see Figures 4 and 5).

Figure 4: Show Java Console
Figure 5: Hide Java Console

I recommend using “JDK with Managed Console” for all kinds of Windows applications. The console is invisible to the user, but the developer can show it to receive a full thread dump or to check for available exceptions. Of course, you can redirect the available exceptions to a log file that the user can send you, but you cannot redirect full thread dump to this log file.

Dress It Up with an Icon
If you want to specify an icon for the .exe file, click on the ‘café’ icon. It will show the “Open file” dialog from where you can select your desired icon. The last action is to specify an output location in the “File:” text field. Enter “c:J2ExeDemoinMyServer.exe” and click the “Generate” button. You’ll find the .exe file in that directory. Start it!

Exercise 2: Exploiting the Windows Tray Bar
Don’t be afraid—using the tray bar is easy! Start “J2TrayExe” and follow the same steps you did in the previous example. The only difference is you set the classpath to “-classpath .;wintray.jar” instead of “-classpath . server.MyServer”. Press the “Generate” button and check the “c:J2ExeDemoin” directory. You will find two files there: “MyServer.exe” (tray variant now) and “wintray.jar”. Move the “wintray.jar” into “c:J2ExeDemolib” since the classpath expects it there.

Now you can start “MyServer.exe”. If your application is a Windows application, try to close it. If it’s a console application, near the minimize, maximize, and close buttons you’ll see an additional button that minimizes the application right into the tray bar. In either case, you will see your application in the tray bar. You can maximize it by double clicking it, and you can show the tray menu by right clicking on it (see Figure 6).

Figure 6: Tray Menu

Next, unzip the “wintray.jar” file, which contains two important java classes:

  1. “” — adds menu items in the tray popup menu; sets icons for the menu items; checks/unchecks or enables/disables menu items; and receives events back in Java
  2. “”— receives events back in Java where you can process them

Now just take the following steps to employ the Windows tray bar in your Java applications:

1) Add Listener to Handle the Close Operation.
Minimize the .exe into the tray bar, right click on the tray icon, and then exit. The icon will disappear and then reappear some minutes later because, in order to perform a soft shutdown, the Java code does not process the close operation. This way, your code can close some connections, save important data, and then quit.

Add the following line in the import section:


Next, add these lines at the end of the main method of

if (WinTray.isWinTrayAvailable()) {  WinTrayListener wtl = new WinTrayListener() {    public void actionPerformed(int code) {      System.out.println("event: " + code);      if (code == 0) System.exit(0);    }   };  WinTray.addWinTrayListener(wtl);}

Kill the MyServer process from Task Manager and start a new one. Try again to close it from the Tray menu. Now the icon disappears permanently. If you check in Task Manager, you’ll see that this process no longer exists.

2) Add Custom Menu Items in the Tray Menu.
This step creates three separate menu items without icons:

  • enabled
  • disabled
  • checked

You can provide specific icons for these items later using the “addTrayMenuIcon” method of the WinTray class. Note that checked menu items cannot have icons because the checkmark acts as an icon for them.

Add the following lines immediately after registering the listener, compile the class, and then restart the application:

WinTray.addWinTrayListener(wtl);...WinTray.addTrayMenuItem("java action 1", 100, -1);WinTray.addTrayMenuItem(null, 101, -1);WinTray.addTrayMenuItem("java action 2", 102, -1);WinTray.enableTrayMenuItemByID(102, false);WinTray.addTrayMenuItem(null, 103, -1);WinTray.addTrayMenuItem("java action 3", 104, -1);WinTray.checkTrayMenuItemByID(104, true);....

Next, minimize the application, right click it, and select any new items. Then restore the application from the tray bar and show its console (if it was hidden; see Figure 7). You should see the action code dump.

Figure 7: Event Is Processed

3) Start Your Application Minimized
Since most servers work in the background, the tray bar is the ideal place for them. Therefore, you should minimize your application in the tray bar at startup (or at any time, really) using the WinTray class:


Alternately, you can restore it from the tray bar using the same class:


Exercise 3: Run a Java Server as a Windows Service
To create a Windows Service, use the J2WinService component of the J2Exe download and simply repeat the same instructions you followed with J2Exe in the first part of the “Exercise 1: Develop a Simple Java Application with Its Own .exe” section. However, after reviewing your “Input” options and before choosing your “Output” options, select “Service” (See Figure 8) and enter the following additional information:

  1. Service name: MyServer
  2. Service description: MyServer Description
  3. Interact with the desktop: checked
  4. Service type: Service that runs in its own process

Start type: Service started on demand or Service started automatically during system startup.

Figure 8: Service Options

To install this service, write “MyServer /install” in the command prompt. To uninstall it, write “MyServer /uninstall”.

Find Your Application’s Balance
Java’s power is its platform independence, but it comes at a cost—the specific features of each platform. The best approach is to build platform-independent applications that preserve the platform-specific features of their target environments. I hope this article helps you to find that golden balance.


About Our Editorial Process

At DevX, we’re dedicated to tech entrepreneurship. Our team closely follows industry shifts, new products, AI breakthroughs, technology trends, and funding announcements. Articles undergo thorough editing to ensure accuracy and clarity, reflecting DevX’s style and supporting entrepreneurs in the tech sphere.

See our full editorial policy.

About Our Journalist