patternjavaMinor
Swing GUI in Java
Viewed 0 times
guiswingjava
Problem
I'm learning Java at the moment and I'm currently trying to make a GUI using Swing. I've done some reading and people usually prefer and advice to use composition instead of inheritance of e.g.
I'm trying to code the GUI by hand instead of using the GUI builders, since they all generate a lot of code and I want to have a proper understanding of what's happening, and I can't seem to do that with the builders.
Questions: Is this a proper use of 'composition' over inheritance, in this case of using
Also: Swing is not thread-safe, so I read that it's good to use
JFrames.I'm trying to code the GUI by hand instead of using the GUI builders, since they all generate a lot of code and I want to have a proper understanding of what's happening, and I can't seem to do that with the builders.
Questions: Is this a proper use of 'composition' over inheritance, in this case of using
JFrames? I want the code behind the GUI to be as efficient as possible, before I begin on expanding the GUI.Also: Swing is not thread-safe, so I read that it's good to use
invokeLater. Am I using it correctly? Can I use it like that in the main, or should it go under the createGUI method?package com.company;
import javax.swing.*;
public class Main {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
Main initiateProgram = new Main();
initiateProgram.createGUI();
}
});
}
public void createGUI() {
JFrame programGUI = new JFrame("GUI Program");
programGUI.setSize(500, 500);
programGUI.setLocationRelativeTo(null);
programGUI.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
programGUI.setVisible(true);
// And here on, an ActionListener for e.g. a button...
}
}Solution
Yes, that is proper use of composition over inheritance. Although some may say this is actually aggregation, due to the nature of Swing.
Composotion is the act of one object owning another object. When
Aggregation is a similar concept, except the composed objects do not become garbage. Composition is a "has-a" relationship, while aggregation is a "uses-a" relationship. Aggregation is another form of composition, with the difference being ownership (no ownership when using aggregation).
When you create a
It's recommended to avoid putting logic in your constructors. It helps lower the cost of actually creating the object, as well as makes testing easier. I recommend adding your components to a
The way you use
To remove the logic from your constructor, you should pass in the
Your
This is referred to as Dependency Injection. The idea is that
The benifits of this include avoiding creating garbage objects (creating
You shouldn't size your frame directly. You shouldn't size any component directly. Instead, use a layout manager to handle the size and location of your components.
Once you have chosen a layout manager, size your frame by using
Composotion is the act of one object owning another object. When
Main becomes garbage, so should the objects it's composed of.Aggregation is a similar concept, except the composed objects do not become garbage. Composition is a "has-a" relationship, while aggregation is a "uses-a" relationship. Aggregation is another form of composition, with the difference being ownership (no ownership when using aggregation).
When you create a
JFrame, the window is also referenced "behind the scenes", and can be accessed via Window.getWindows(). Even if Main becomes garbage, the window will still exist until you call dispose() on it.It's recommended to avoid putting logic in your constructors. It helps lower the cost of actually creating the object, as well as makes testing easier. I recommend adding your components to a
JPanel, then passing that to the constructor to be added to the frame via JFrame#setContentPane(Container).The way you use
invokeLater is fine in the sense that it forwards GUI code to the Event Dispatch Thread, which is what you always want to do. But hiding it in the constructor could lead to confusions. From outside of the class, we cannot be sure of whats inside the constructor. Someone may assume that the code is not already forwarded to the EDT, leading them to them wrapping the constructor call in an invokeLater aswell, resulting in posting 2 events to the EDT.To remove the logic from your constructor, you should pass in the
JFrame once you have prepared it:public static void main(String[] args) {
EventQueue.invokeLater(() -> {
JFrame frame = new JFrame();
//add components
new Test(frame);
});
}Your
Test class would then look something like this:class Test {
private JFrame frame;
public Test(JFrame frame) {
this.frame = frame;
}
//...
}This is referred to as Dependency Injection. The idea is that
Test needs a frame. Without a frame, there shouldn't be a Test object. Create Test objects when you are certain that there is a frame for it to use.The benifits of this include avoiding creating garbage objects (creating
Test would be pointless if there was a problem creating the frame it needs), as well as allowing you to pass different frames, rather than having the frame hard-coded into it. The ability to use different frames, rather than be forced to use a single hard-coded frame, is referred to as Inversion of control, and increases reusability.You shouldn't size your frame directly. You shouldn't size any component directly. Instead, use a layout manager to handle the size and location of your components.
Once you have chosen a layout manager, size your frame by using
pack(), which sizes the frame based on the components inside of it.Code Snippets
public static void main(String[] args) {
EventQueue.invokeLater(() -> {
JFrame frame = new JFrame();
//add components
new Test(frame);
});
}class Test {
private JFrame frame;
public Test(JFrame frame) {
this.frame = frame;
}
//...
}Context
StackExchange Code Review Q#123480, answer score: 4
Revisions (0)
No revisions yet.