Post Thumbnail

How to Build a Desktop Application With Java

Overview

We’ll build a simple desktop application that’ll translate English text to Morse Code and vice-versa in very simple steps. We’ll also dive into Java Graphics User Interface (GUI) classes and how to stitch them together to make a beautiful desktop interface.

This is going to be an introductory lesson into the world of Graphics User Interface (GUI) with Java Programming language. (confession: I love Java)

Translation Logic

First, before going into the graphics part, let’s look at the business logic.

In Java, HashMap is a key-value data structure. This means we can make reference to an entry using it’s key. This makes it suitable for us to use in building our dictionary of English letters and their corresponding Morse code:

1
2
3
4
5
6
7
private HashMap<String, String> englishToMorseLib = new HashMap<>();
englishToMorseLib.put("A", ".-");
englishToMorseLib.put("B", "-...");
englishToMorseLib.put("C", "-.-.");

//...
//link to full source code on Github is giving at the end of the article 

Now that we’ve stored our raw data, we need to create two methods: one to translate the English text to Morse code and the other to do the opposite.

In both cases, the text is split using a regex that matches whitespace and newline characters. Each of the resulting arrays is processed using Streams API for efficiency:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
//this method will convert English Words to Morse Code

public String englishWordToMorseWord(String englishWord) {

    StringBuffer buffer = new StringBuffer();
    Stream.of(englishWord.split("[\\s\\n]"))
            .forEach( s -> {
                for(char c: s.toCharArray()) {
           buffer.append(englishToMorseLib.containsKey(String.valueOf(c).toUpperCase()) ? englishToMorseLib.get(String.valueOf(c).toUpperCase()) + " " : "?? ");
                }
                buffer.append(" / ");
            });

    return buffer.toString();
}

//this method will convert Morse code to English Word

public String morseWordToEnglishWord(String morseWord) {
    StringBuffer buffer = new StringBuffer();
    Stream.of(morseWord.split("[\\s\\n]"))
            .filter((s) -> s != null && !s.isEmpty())
            .forEach( s -> {
                if(s.equalsIgnoreCase("/") || s.equalsIgnoreCase("|")) {
                    buffer.append(" ");
                } else {
                    buffer.append((morseToEnglishLib.containsKey(s) ? morseToEnglishLib.get(s) : "?? ").toLowerCase());
                }
            });

    return buffer.toString();
}

GUI Elements In Java

Java has a rich set of GUI elements that serve as building blocks for a complete GUI Desktop Application.

JFrame

The top-most layer of Java GUI is the JFrame. It’s the outermost container that houses other elements or containers. It is the part of the app with the close, minimize and maximize buttons. The following lines of code will create a JFrame Object:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
//create JFrame Instance

JFrame frame = new JFrame(); 
frame.setTitle("Morse Code Translator by Seun Matt (@SeunMatt2)");
frame.setLayout(new BorderLayout()); 

//add other containers and elements to the JFrame
frame.add(mainPanel, BorderLayout.CENTER); 
frame.setSize(new Dimension(800, 650)); 

//this terminate the app when the close button is clicked
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 

//this will make the app to always display at the centre
frame.setLocationRelativeTo(null);
 
//well, I don't want you to resize the window
frame.setResizable(false);

//and yes this will show the visible frame/app
frame.setVisible(true);

(Side-Note: Object Oriented Programming is sweet with Java)

What the code above does is to create an instance of the JFrame object, set parameters like title, layout, size, location and as well set the behaviour of the JFrame like the ability to resize the frame and its visibility.

JPanel

This is a container, meaning it holds other elements together. The child elements are arranged in a specific other using layout managers as we will later find out. The following lines of code are responsible for creating the button row at the bottom of the Morse Text area, to the right of the application:

1
2
3
4
5
6
7
JPanel morseControlPanel = new JPanel(); 
//set the layout style
morseControlPanel.setLayout(new FlowLayout(FlowLayout.RIGHT));
//add the Morse >> English button
morseControlPanel.add(morseToEnglishBt);
//add the Clear Text >> button
morseControlPanel.add(clearMorseText);

Other Elements Used in the App

Other Elements used in the program are:

  • JButton: Clickable buttons for performing special actions. For example, the clear text button beneath the English text is created thus: JButton clearEnglishText = new JButton("<< Clear Text");

  • JLabel: Well from the name we can infer that it is a label and labels are used for - labelling things. Here is the code that created the “English Text” at the top of the English text area:

1
2
JLabel englishTextLabel = new JLabel("English Text");
englishTextLabel.setHorizontalAlignment(SwingConstants.CENTER);
  • JTextArea: This element is the container where we type texts into. JTextArea is meant for multi-line texts. (Note: These elements are Java Objects and thus their behaviour and properties can be specified. Like alignment, text, location etc. You can even bind events to them as we will see later):
1
2
3
4
5
6
7
//create the object instance
JTextArea englishTextArea = new JTextArea(20,20);
//set the object properties and behaviour
englishTextArea.setText("Hello World");
englishTextArea.setLineWrap(true);
englishTextArea.setWrapStyleWord(true);
englishTextArea.setMargin(new Insets(5, 5, 5,5));
  • LayoutManagers: Layout managers specify how elements in a container will be arranged. In this application, we used FlowLayout and BorderLayout to specify how elements are laid out.

With FlowLayout, elements will be laid out in sequence and in order in which they are added to the container. BorderLayout, on the other hand, will arrange GUI elements to the SOUTH, NORTH, EAST, WEST and CENTER:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
//this flowlayout will show the Clear Text button first
//followed by the English >> Morse button
//and they will be aligned to the left
JPanel englishControlPanel = new JPanel(new FlowLayout(FlowLayout.LEFT));
englishControlPanel.add(clearEnglishText);
englishControlPanel.add(englishToMorseBt);


//this panel uses the BorderLayout manager
//elements are added with specification of where they will be located
JPanel englishTextPanel = new JPanel();
englishTextPanel.setLayout(new BorderLayout());
englishTextPanel.add(englishTextLabel, BorderLayout.NORTH);
englishTextPanel.add(new JScrollPane(englishTextArea), BorderLayout.CENTER);
englishTextPanel.add(englishControlPanel, BorderLayout.SOUTH);

Event Listeners

Events bring GUI elements to live; such that when a button is clicked, an event is generated in the system and consequently triggering registered event listeners.

The following code is responsible for registering the buttons for an ActionEvent that is fired when a button is clicked. (lambda expression at work #java8):

1
2
3
4
5
6
7
8
9
englishToMorseBt.addActionListener((e) -> {
    String english = englishTextArea.getText().trim();
    morseTextArea.setText(englishWordToMorseWord(english));
});

morseToEnglishBt.addActionListener((e) -> {
    String morse = morseTextArea.getText().trim();
    englishTextArea.setText(morseWordToEnglishWord(morse));
});

And this is where we registered the TextAreas to listen for Keyboard events and automatically execute translation when the space bar or backspace key is pressed:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
englishTextArea.addKeyListener(new KeyAdapter() {

    @Override
    public void keyTyped(KeyEvent e) {
        //when space bar is pressed (or back space) do the conversion
        if(Character.isWhitespace(e.getKeyChar()) || e.getKeyCode() == KeyEvent.VK_BACK_SPACE) {
            morseTextArea.setText(englishWordToMorseWord(englishTextArea.getText()));
        }
    }
});

 
morseTextArea.addKeyListener(new KeyAdapter() {

    @Override
    public void keyTyped(KeyEvent e) {
        //when space bar is pressed (or back space) do the conversion
        if(Character.isWhitespace(e.getKeyChar()) || e.getKeyCode() == KeyEvent.VK_BACK_SPACE) {
            englishTextArea.setText(morseWordToEnglishWord(morseTextArea.getText()));
        }
    }
});

Main Method

In the main method, which is the entry point for all Java applications, the look-and-feel of the app was set to NimbusLookAndFeel which look more pretty than the default Java look and feel. Afterwards, the app is fired on:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
public static void main(String[] args) {

    try {
        UIManager.setLookAndFeel("javax.swing.plaf.nimbus.NimbusLookAndFeel");
    } catch (Exception e) {
        e.printStackTrace();
    }

    SwingUtilities.invokeLater(() -> {
        new MorseCodeTranslator();
    });
}

The complete source code is available on this GitHub repo. You can find instructions to contribute and run the app in the repo’s README (remember to give it a star).

Happy Coding