DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports Events Over 2 million developers have joined DZone. Join Today! Thanks for visiting DZone today,
Edit Profile Manage Email Subscriptions Moderation Admin Console How to Post to DZone Article Submission Guidelines
View Profile
Sign Out
Refcards
Trend Reports
Events
Zones
Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Partner Zones AWS Cloud
by AWS Developer Relations
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Partner Zones
AWS Cloud
by AWS Developer Relations
The Latest "Software Integration: The Intersection of APIs, Microservices, and Cloud-Based Systems" Trend Report
Get the report
  1. DZone
  2. Coding
  3. Languages
  4. Clean Code with Swing and Scala

Clean Code with Swing and Scala

Jens Schauder user avatar by
Jens Schauder
·
Jul. 27, 11 · Interview
Like (0)
Save
Tweet
Share
9.41K Views

Join the DZone community and get the full member experience.

Join For Free

I guess everybody who knows Java and Swing also knows the Swing Tutorial. It is a great source of information if you want to learn Swing. It is also a major catastrophy when it comes to structuring code. The problem is: Lots of people miss critical information contained in the tutorial like ‘Everything concerned with Swing must happen in the EDT’ but they seem to suck up the messy way to structure code like a sponge.

This might result in code like the one below. It is actually Scala code, but that shouldn’t matter much. The only piece that is a little special are the calls to Binder, which is a little Swing Binding Framework which I introduced a couple of weeks ago.

private def createPersonPanel(p : PersonEditor) = {

            val panel = new JPanel()
            val layout = new GridBagLayout()
            val c = new GridBagConstraints()
            c.gridx = 0
            c.gridy = 0
     
            panel.setLayout(layout)
     
            c.fill = 0
            panel.add(new JLabel("firstname"), c)
     
            c.fill = 1
            c.gridx += 1
            c.weightx = 1
            val firstnameTF = new JTextField()
            panel.add(firstnameTF, c)
            Binder.bind(p.firstname, firstnameTF)
     
            c.fill = 0
            c.weightx = 0
            c.gridx = 0
            c.gridy += 1
     
            panel.add(new JLabel("lastname"), c)
            c.fill = 1
     
            c.gridx += 1
            val lastnameTF = new JTextField()
            Binder.bind(p.lastname, lastnameTF)
            panel.add(lastnameTF, c)
            c.fill = 0
            c.weightx = 1
            c.gridy += 1
            c.anchor = GridBagConstraints.SOUTHEAST
            val button = new JButton("save")
            Binder.bind(p.save, button)
            panel.add(button, c)
            panel
        }

What is so bad about this piece of crap … ähm … code?

The method is long. 38 lines is about 10 times longer than healthy for a method.

There is tons of code duplication.

The method does lots of different things: creating components, adding them to a panel, configuring the layout.

There is a strong dependency on the order of commands. We can’t just move stuff up or down in the method and still hope the result will be something reasonable, even if we stick to rearrangements allowed by the compiler.

All this together makes the method extremely hard to understand. How long does it take to understand what kind of GUI results? Don’t bother to much, I help. It looks like this:

and if you resize it, it looks like this

Arguably the result looks just as ugly as the code, but once the code is clean we might be able to improve on the visual design as well.

If you don’t see it in the code, you might see it in the images: There are three different ways JComponents are handled by the method: JLabels are in the left column and don’t resize. The JTextFields are in the right column and do resize and the JButton doesn’t resize and is in the buttom right. In the code this is completely hidden in the manipulation of the GridBagConstraint. So lets make it explicit in the code:

private def addToLabelColumn(

            panel : JPanel,
            component : JComponent,
            row : Int) {
            val c = new GridBagConstraints()
            c.gridx = 0
            c.gridy = row
            c.weightx = 0
            c.fill = 0
            panel.add(component, c)
        }
     
        private def addToComponentColumn(
            panel : JPanel,
            component : JComponent,
            row : Int) {
            val c = new GridBagConstraints()
            c.gridx = 1
            c.gridy = row
            c.weightx = 1
            c.fill = 1
            panel.add(component, c)
        }
     
        private def addButton(
            panel : JPanel,
            component : JButton,
            row : Int) {
            val c = new GridBagConstraints()
     
            c.weightx = 1
            c.gridx = 1
            c.gridy = row
            c.fill = 0
            c.anchor = GridBagConstraints.SOUTHEAST
            panel.add(component, c)
        }
     
        private def createPersonPanel(p : PersonEditor) = {
            val panel = new JPanel()
            val layout = new GridBagLayout()
            panel.setLayout(layout)
     
            addToLabelColumn(panel, new JLabel("firstname"), 0)
     
            val firstnameTF = new JTextField()
            Binder.bind(p.firstname, firstnameTF)
            addToComponentColumn(panel, firstnameTF, 0)
     
            addToLabelColumn(panel, new JLabel("lastname"), 1)
     
            val lastnameTF = new JTextField()
            Binder.bind(p.lastname, lastnameTF)
            addToComponentColumn(panel, lastnameTF, 1)
     
            val button = new JButton("save")
            Binder.bind(p.save, button)
            addButton(panel, button, 2)
            panel
        }

I introduced three methods. One for adding a JLabel, one for adding a JComponent and one for adding JButtons. These handle the arrangement of components on a JPanel. The total length of the code increased because we create the GridBagConstraints insided the methods and have to set all properties and don’t rely anymore on the previous step to leave the constraint in a specific state.

If we now look at the createPersonPanel we’ll get a strong fealing of repetition in various places:

  • each call to add* methods takes the same JPanel as an argument. We can improve on this by creating a Builder wich crates the panel, contains the add* methods and can return the fully configured panel at the end.
  • for each property we create a JLabel, a JTextField, bind the property to the later and add both to the JPanel. We can fix this by encapsulating it in a seperate method.

The result might look like this:

  case class PanelBuilder() {
        val panel = new JPanel()
        val layout = new GridBagLayout()
        panel.setLayout(layout)
 
        def add(components : (JLabel, JComponent), row : Int) {
            addToLabelColumn(components._1, row)
            addToComponentColumn(components._2, row)
        }
 
        def add(
            component : JButton,
            row : Int) {
            val c = new GridBagConstraints()
 
            c.weightx = 1
            c.gridx = 1
            c.gridy = row
            c.fill = 0
            c.anchor = GridBagConstraints.SOUTHEAST
            panel.add(component, c)
        }
 
        private def addToLabelColumn(
            component : JComponent,
            row : Int) {
            val c = new GridBagConstraints()
            c.gridx = 0
            c.gridy = row
            c.weightx = 0
            c.fill = 0
            panel.add(component, c)
        }
 
        private def addToComponentColumn(
            component : JComponent,
            row : Int) {
            val c = new GridBagConstraints()
            c.gridx = 1
            c.gridy = row
            c.weightx = 1
            c.fill = 1
            panel.add(component, c)
        }
 
    }
 
    private def create(name : String, property : Property[String]) : (JLabel, JComponent) = {
        val textField = new JTextField()
        Binder.bind(property, textField)
        (new JLabel(name), textField)
    }
 
    private def create(name : String, action : => Unit) = {
        val button = new JButton("save")
        Binder.bind(action, button)
        button
    }
 
    private def createPersonPanel(p : PersonEditor) = {
        val builder = PanelBuilder()
 
        builder.add(create("firstname", p.firstname), 0)
        builder.add(create("lastname", p.lastname), 1)
        builder.add(create("save", p.save), 2)
 
        builder.panel
    }

The PanelBuilder has now two simple public add methods. In order to imitate the method signitures in Java we would have to create a couple of helper classes and interfaces. It would make the code less compact but this shouldn’t be a serious problem. Creation of the various components is just as the binding extracted in two create Methods. The createPersonPanel has now only 5 lines of code. Adding another property to the form should be trivial. Changing the extremely simplistic layout should be trivial and is at least limited to a single small class. I think this is pretty much OK for a first step toward clean swing code. So I leave it like it is right now. Although I do have further plans for this.

I hope most of you agree that the code is much easier to understand and maintain in the form it is right now. But is it really worth the effort? Some might say no. If the whole application would consist of only this little panel. I would agree. But a Swing application typically does not have a single panel with two textfields and a button. But tens or even hundreds of panels. Many consisting of large collections of components. If you have to maintain such a monster, would you prefer createPersonPanel methods like the last one, or would you prefer the first version? What if the customer if finally fed up with your crappy layout and insists on proper spacing between the labels and the JTextFields or other components?

All this is pretty nice when you start a new Swing application. But what if you have an existing Swing application? One with convoluted code just as the Swing Tutorial taught you? Well … start changing it now. Don’t sit down for two months and rewrite all your code, but find pieces of code duplication and extract them. It will be a long way, but you wont reach the end if you don’t start walking.

But what if you are not using Swing, but writing a web application? Well it really shouldn’t matter much. Your PanelBuilder might be written in JavaScript, or create HTML, but the principle is the same: Seperate creation of components, layout of components and binding of components to properties and actions.

 

From http://blog.schauderhaft.de/2011/06/26/clean-code-with-swing-and-scala/

Scala (programming language)

Opinions expressed by DZone contributors are their own.

Popular on DZone

  • What Are the Different Types of API Testing?
  • 19 Most Common OpenSSL Commands for 2023
  • A Beginner’s Guide To Styling CSS Forms
  • Assessment of Scalability Constraints (and Solutions)

Comments

Partner Resources

X

ABOUT US

  • About DZone
  • Send feedback
  • Careers
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 600 Park Offices Drive
  • Suite 300
  • Durham, NC 27709
  • support@dzone.com
  • +1 (919) 678-0300

Let's be friends: