Swing is an old GUI framework that is still useful and competitive by 2024 standards. It comes with Java so no extra installation is needed. Downside is that you can only target desktop platforms, with no web or mobile support, unlike JavaFX. It has a lot of widgets with capabilities to create your own custom ones.
Enough intro. Here is a simple, cross-platform Swing GUI app example that does not look horribly outdated (ie. not Metal). It uses Nimbus look & feel (which is easily customizable) and works with Java 11+. Screenshots (scaled to same resolution):
Java 17, MacOS |
Java 11, Manjaro |
The results are respectably similar, with some differences in line height. You can compile the below source with:
javac -g:none Chat.java jar cvfe Chat.jar Chat Chat*.class rm Chat*.class
Double-clicking the jar file should open the app, and it is less than 3200 bytes on either platform. Chat.java file:
import java.awt.BorderLayout; import java.awt.Dimension; import java.awt.event.KeyAdapter; import java.awt.event.KeyEvent; import javax.swing.JButton; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JMenu; import javax.swing.JMenuBar; import javax.swing.JMenuItem; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JTextArea; import javax.swing.JTextField; import javax.swing.UIManager; import javax.swing.UnsupportedLookAndFeelException; import javax.swing.plaf.FontUIResource; import javax.swing.plaf.nimbus.NimbusLookAndFeel; class Chat { public static void changeFontSize(int delta) { var def = UIManager.getLookAndFeelDefaults(); for (var key : def.keySet()) { try { var fr = (FontUIResource) def.get(key); var nf = new FontUIResource(fr.getName(), fr.getStyle(), fr.getSize() + delta); def.put(key, nf); } catch (ClassCastException ex) {} } } public static void main(String args[]) { try { UIManager.setLookAndFeel(new NimbusLookAndFeel()); } catch (UnsupportedLookAndFeelException ex) { System.err.println(ex.toString()); return; } changeFontSize(3); // Creating the Frame var frame = new JFrame("Chat App"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setMinimumSize(new Dimension(650, 400)); frame.setLocationRelativeTo(null); // screen center // Creating the MenuBar and adding menus var menus = new JMenuBar(); var file = new JMenu("File"); var open = new JMenuItem("Open"); var save = new JMenuItem("Save"); file.add(open); file.add(save); var help = new JMenu("Help"); var about = new JMenuItem("About"); help.add(about); menus.add(file); menus.add(help); about.addActionListener(ae -> { JOptionPane.showMessageDialog(frame, "Chat v0.1", "About", JOptionPane.INFORMATION_MESSAGE); }); // Creating the panel at bottom and adding widgets var panel = new JPanel(false); // single-buffered, not visible var label = new JLabel("Enter Text"); var msgBox = new JTextField(20); var send = new JButton("Send"); var reset = new JButton("Reset"); panel.add(label); // Components Added using Flow Layout panel.add(msgBox); panel.add(send); panel.add(reset); // Text Area at the center var text = new JTextArea(); var scroll = new JScrollPane(text); msgBox.addKeyListener(new KeyAdapter() { @Override public void keyTyped(KeyEvent ke) { if (ke.getKeyChar() == '\n') { // send when pressed enter send.doClick(); } } }); send.addActionListener(ae -> { var msg = msgBox.getText(); if (msg != null && msg.length() > 0) { text.append(msg + "\n"); msgBox.setText(null); } }); reset.addActionListener(ae -> { text.setText(null); }); // Adding Components to the frame. frame.add(scroll, BorderLayout.CENTER); frame.add(panel, BorderLayout.SOUTH); frame.add(menus, BorderLayout.NORTH); frame.setVisible(true); } }