patternjavaMinor
Heavily nested anonymous classes for Swing UIs
Viewed 0 times
anonymousheavilyuisnestedswingforclasses
Problem
Oftentimes, I write small little dialogs or forms without a UI builder. I usually find myself having a lot of "container" panel variables that just float around. I found this leads to time-wasting experiences.
Where did I put that BorderLayout panel?
Oh right, here it is.
Wait, never mind. That one has a GridLayout.
A while ago, I had the idea to nest widgets in anonymous classes, directly in
Pros
Cons
Below is a simple (Java 8) frame that shows a button and a label. I realise that this same layout could have been made with fewer panels, but I'm presenting it as an overly explicit example of my approach.
```
import javax.swing.*;
import java.awt.*;
public class TestFrame extends JFrame {
public TestFrame() {
super("A Frame");
add(new JPanel() {
{
setLayout(new BorderLayout());
setBackground(Color.LIGHT_GRAY);
add(new JPanel() {
{
setLayout(new BorderLayout());
setOpaque(false);
add(new JLabel("A label", JLabel.LEFT) {
{
setBorder(BorderFactory.createEmptyBorder(0, 10, 0, 10));
setFont(getFont().deriveFont(Font.BOLD));
Where did I put that BorderLayout panel?
Oh right, here it is.
Wait, never mind. That one has a GridLayout.
A while ago, I had the idea to nest widgets in anonymous classes, directly in
add calls. This way, a simple layout has fewer variables that get in the way of digesting the code's logic since every component is nicely indented in its own scope.Pros
- Component hierarchy is obvious, as are component attributes like colors and fonts
- Code is cleaner, with less dummy container variables
- Forces component logic to be encapsulated directly in the component (i.e. not 50 lines up or below the component initialization: saves time)
- I found it easier to come back to code written in this style after a couple months and still understand the layout.
Cons
- Might bloat generated code size, because all the Swing constants would have to be written to each classfile
Below is a simple (Java 8) frame that shows a button and a label. I realise that this same layout could have been made with fewer panels, but I'm presenting it as an overly explicit example of my approach.
```
import javax.swing.*;
import java.awt.*;
public class TestFrame extends JFrame {
public TestFrame() {
super("A Frame");
add(new JPanel() {
{
setLayout(new BorderLayout());
setBackground(Color.LIGHT_GRAY);
add(new JPanel() {
{
setLayout(new BorderLayout());
setOpaque(false);
add(new JLabel("A label", JLabel.LEFT) {
{
setBorder(BorderFactory.createEmptyBorder(0, 10, 0, 10));
setFont(getFont().deriveFont(Font.BOLD));
Solution
Anonymous constructors are very confusing for many people. They don't correspond well to people's expectations, and are not common knowledge.
I would recommend against them on principle.
Having said that, I can see how you think this has helped reduce your code boilerplate, but, you need to be consistent about it then. Currently your class is defined as:
when really, that should be:
If you are going to be unconventional, then you at least need to be consistently unconventional.
Having said all of that, you really should use a style that is more conventional just so others can read your code better. The indentation levels on their own are a distraction with the addition of the anonymous blocks.
Oh, there's one other item that needs to be said, with all the anonymous classes there, your stack traces for any exceptions are going to be much harder to read without the code in hand too. You lose all the benefits of named classes. This will hamper your debug time.
I would recommend against them on principle.
Having said that, I can see how you think this has helped reduce your code boilerplate, but, you need to be consistent about it then. Currently your class is defined as:
public class TestFrame extends JFrame {
public TestFrame() {
super("A Frame");
add(new JPanel() {
{when really, that should be:
public class TestFrame extends JFrame {
{
setName("A Frame");
add(new JPanel() {
{If you are going to be unconventional, then you at least need to be consistently unconventional.
timesClicked should probably be an AtomicInteger so you can deal with some concurrency in the clicked event - or, rather, so you can read it from a different thread later. Lambdas with side-effects should be avoided.Having said all of that, you really should use a style that is more conventional just so others can read your code better. The indentation levels on their own are a distraction with the addition of the anonymous blocks.
Oh, there's one other item that needs to be said, with all the anonymous classes there, your stack traces for any exceptions are going to be much harder to read without the code in hand too. You lose all the benefits of named classes. This will hamper your debug time.
Code Snippets
public class TestFrame extends JFrame {
public TestFrame() {
super("A Frame");
add(new JPanel() {
{public class TestFrame extends JFrame {
{
setName("A Frame");
add(new JPanel() {
{Context
StackExchange Code Review Q#88090, answer score: 4
Revisions (0)
No revisions yet.