I've always coded my graphical applications in Java by extending the JFrame
class like so:
public class CalculatorApp extends JFrame {
// GUI components are declared as member variables of JFrame
private final JLabel answerLabel;
private final JButton sumButton;
private final JButton divideButton;
...
// Create and display the GUI
public CalculatorApp() {
setTitle("A Calculator");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
...
// Initialize components
answerLabel = new JLabel("Your answer will appear here");
sumButton = new JButton("Sum");
sumButton.addActionListener((ActionEvent e) -> {
sum();
});
...
// Make visible
pack();
setVisible(true);
}
// Actions performed by the user; these methods have access to
// the GUI components to grab the user input (eg. TextField.getText())
// and then update the GUI with the result (eg. answerLabel.setText()).
public void sum() {
...
}
public void divide() {
...
}
...
public static void main(String[] args) {
new CalculatorApp();
}
}
Although recently I've learned that this is not very good practice since you're putting your specific application's function into a JFrame
- something that really shouldn't have the function of a calculator, for example. I've found that trying to create applications with more and more features with this approach leads to really horribly organized code because there's no line between GUI & input verification code, and the actual application's features.
So what's the best way to structure a program like this?
I've outlined the only sensible alternative I could think of below.
Handlers
This structure separates the function of the application from the GUI by putting the GUI nicely into its own little class that can be created and shown, but has the drawback of having to manage a lot of annoying handlers. The handlers are a way to give the application function to the GUI. This structure is also easier to convert to other JWindow
s like JDialog
because the entire class hierarchy doesn't have to be changed.
public class CalculatorApp {
// Create the GUI and pass it the handlers
public CalculatorApp() {
new CalculatorAppGUI(
new SumHandlerImpl(),
new DivideHandlerImpl(),
...
).show();
}
// All of the application function is in the handlers
private class SumHandlerImpl() implements SumHandler {
public double sum(double a, double b) {
return a + b;
}
}
private class DivideHandlerImpl() implements DivideHandler {
public double divide(double a, double b) {
return a / b;
}
}
...
public static void main(String[] args) {
new CalculatorApp();
}
}
public class CalculatorAppGUI {
// Handlers that perform application function are stored as member variables
private final SumHandler sumHandler;
private final DivideHandler divideHandler;
// GUI components are declared as member variables
private final JPanel mainPanel;
private final JLabel answerLabel;
private final JButton sumButton;
private final JButton divideButton;
...
public CalculatorAppGUI(SumHandler sumHandler, DivideHandler divideHandler) {
// Store handlers
this.sumHandler = sumHandler;
this.divideHandler = divideHandler;
// Initialize components
mainPanel = new JPanel(new SomeLayoutManager());
answerLabel = new JLabel("Your answer will appear here");
sumButton = new JButton("Sum");
sumButton.addActionListener((ActionEvent e) -> {
double answer = sumHandler.sum(/* Values from GUI */);
answerLabel.setText(String.valueOf(answer));
});
...
mainPanel.add(answerLabel);
}
// Create a frame for the GUI and display it
public void show() {
JFrame frame = new JFrame();
frame.setTitle("A Calculator");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
...
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setVisible(true);
}
// Nested static handler interfaces
@FunctionalInterface
public static interface SumHandler {
public double sum(double a, double b);
}
...
}
The handlers in this case are very simple, but in a larger application they would be much more complicated operations like JoinGameHandler
or whatnot. Here the application function and things like application state (connected to a game or not?) would be stored in the CalculatorApp
class and all the GUI code would be in the CalculatorAppGUI
class. The issue here is that a GUI with a lot of buttons and a lot of features leads to a lot of handlers which doesn't organize very well either (you could end up with a hundred handlers to store for a sufficiently complex application, which is just impractical).
In case it isn't already apparent, I'm 100% self-taught in the area of Java Swing and haven't really been exposed to the standards for this sort of stuff. All help appreciated.