Effortless Java Swing Data Binding: A Guide to Mogwai Framework

This article demonstrates how to implement efficient data binding in Java Swing applications using the Mogwai DataBinding framework. It provides a comprehensive example of binding various Swing components (including JTextField, JComboBox, and JRadioButton) to a POJO model, showcasing bidirectional data synchronization between UI elements and Java objects. The tutorial includes detailed code examples and explanations of key concepts such as BindingInfo initialization, model-to-view, and view-to-model operations, offering developers a practical solution for automating UI data management in Swing applications.

4 Minutes reading time

Behold the masterpiece that AI hallucinated while reading this post:

"How Little POJO Found His Way to the Swing Widget Village"

(after I fed it way too many marketing blogs and memes)

Created using DALL-E 3

AI-Generated: How Little POJO Found His Way to the Swing Widget Village

While you are developing Java Swing based applications, you need a mechanism to bind Java objects to Swing widgets. Project mogwai.sourceforge.net provides a very simple but powerful framework called DataBinding to help you with this task. Here is an example.

Given the following piece of code(the model you want to bind):

import java.util.Collection;
import java.util.HashSet;

public class ExampleModel {

    private String string1;
    private String string2;
    private boolean bool;
    private String selected;
    private String type;
    private Collection<String> entries = new HashSet<String>();
    private String[] entriesArray = new String[0];

    public ExampleModel() {
        entries.add("A");
        entries.add("B");
        entries.add("C");

        entriesArray = new String[]{"D", "E", "F"};
    }

    public String getString1() {
        return string1;
    }

    public void setString1(String string1) {
        this.string1 = string1;
    }

    public boolean isBool() {
        return bool;
    }

     public void setBool(boolean bool) {
        this.bool = bool;
    }

    public String getSelected() {
        return selected;
    }


    public void setSelected(String selected) {
        this.selected = selected;
    }


    public String getString2() {
        return string2;
    }


    public void setString2(String string2) {
        this.string2 = string2;
    }


    public String getType() {
        return type;
    }


    public void setType(String type) {
        this.type = type;
    }


    public Collection<String> getEntries() {
        return entries;
    }


    public void setEntries(Collection<String> entries) {
        this.entries = entries;
    }


    public String[] getEntriesArray() {
        return entriesArray;
    }


    public void setEntriesArray(String[] entriesArray) {
        this.entriesArray = entriesArray;
    }
}

How we want to bind each of the properties to Swing widgets. Here is an example Swing UI with embedded DataBinding code:

import com.jgoodies.forms.layout.CellConstraints;
import com.jgoodies.forms.layout.FormLayout;
import de.mogwai.common.client.binding.adapter.ComboboxModelAdapter;
import de.mogwai.common.client.binding.adapter.RadioButtonAdapter;

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;

/**
 * @author msertic
 */
public class DataBindingTest1 {

    public static void main(String args[]) {

        // Setup the view
        JFrame frame = new JFrame("Test");
        frame.addWindowListener(new WindowAdapter() {
            public void windowClosing(WindowEvent e) {
                System.exit(0);
            }
        });
        frame.setSize(640, 480);

        CellConstraints cons = new CellConstraints();

        FormLayout layout = new FormLayout("90dlu,80dlu:grow",
                "2dlu,p,2dlu,p,2dlu,p,2dlu,p,2dlu,p,2dlu,p,p,p,2dlu");

        JPanel content = new JPanel();
        content.setLayout(layout);

        frame.getContentPane().setLayout(new BorderLayout());
        frame.getContentPane().add(content, BorderLayout.CENTER);

        JLabel label1 = new JLabel("JTextField with value");
        JTextField textfield1 = new JTextField();

        content.add(label1, cons.xy(1, 2));
        content.add(textfield1, cons.xy(2, 2));

        JLabel label2 = new JLabel("JTextField without value");
        JTextField textfield2 = new JTextField();

        content.add(label2, cons.xy(1, 4));
        content.add(textfield2, cons.xy(2, 4));

        JLabel label3 = new JLabel("JCheckBox");
        JCheckBox box3 = new JCheckBox();

        content.add(label3, cons.xy(1, 6));
        content.add(box3, cons.xy(2, 6));

        JLabel label4 = new JLabel("JComboBox bound to Vector");
        JComboBox combo1 = new JComboBox();

        content.add(label4, cons.xy(1, 8));
        content.add(combo1, cons.xy(2, 8));

        JLabel label5 = new JLabel("JComboBox bound to Object[]");
        JComboBox combo2 = new JComboBox();

        content.add(label5, cons.xy(1, 10));
        content.add(combo2, cons.xy(2, 10));

        JLabel label6 = new JLabel("JRadioButton");
        JRadioButton radio1 = new JRadioButton("Radio 1");
        JRadioButton radio2 = new JRadioButton("Radio 2");
        JRadioButton radio3 = new JRadioButton("Radio 3");

        content.add(label6, cons.xy(1, 12));
        content.add(radio1, cons.xy(2, 12));
        content.add(radio2, cons.xy(2, 13));
        content.add(radio3, cons.xy(2, 14));

        //
        //
        // Now, here comes the tricky part !
        //
        //

        // Setup the model
        ExampleModel model = new ExampleModel();
        model.setString1("Wutzpu");
        model.setBool(true);
        model.setSelected("2");

        // Setup the binding
        final BindingInfo binding = new BindingInfo(ExampleModel.class);
        binding.addBinding("string1", textfield1);
        binding.addBinding("string2", textfield2);
        binding.addBinding("bool", box3);
        binding.addBinding("type", combo1);
        binding.addBinding("entries", new ComboboxModelAdapter(combo1));
        binding.addBinding("entriesArray", new ComboboxModelAdapter(combo2));

        RadioButtonAdapter adaptor = new RadioButtonAdapter();
        adaptor.addMapping("1", radio1);
        adaptor.addMapping("2", radio2);
        adaptor.addMapping("3", radio3);
        binding.addBinding("selected", adaptor);

        binding.setDefaultModel(model);

        // Initialize the view !
        // This also forces the collection to model mapping to be initialized !
        binding.model2view();

        // Event listener
        JButton button = new JButton("View 2 Model");

        //
        // This is an example event listener !
        //
        button.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                // Transfer the data to the model
                binding.view2model();

                // Get the model
                ExampleModel model = (ExampleModel) binding.getDefaultModel();

                // Modify the model
                String test = model.getType() + " " + model.getSelected();
                model.setString2(test);

                // Transfer the model to the view
                binding.model2view();
            }
        });
        frame.getContentPane().add(button, BorderLayout.NORTH);

        frame.show();
    }
}

This will generate a full functional Swing UI with bidirectional data binding between the model and the widgets. The tricky part is the initialization and usage of the Mogwai BindingInfo instance. The Initialization works as following:

final BindingInfo binding = new BindingInfo(ExampleModel.class);

binding.addBinding("string1", textfield1);
binding.addBinding("string2", textfield2);
binding.addBinding("bool", box3);
binding.addBinding("type", combo1);
binding.addBinding("entries", new ComboboxModelAdapter(combo1));
binding.addBinding("entriesArray", new ComboboxModelAdapter(combo2));

RadioButtonAdapter adaptor = new RadioButtonAdapter();
adaptor.addMapping("1", radio1);
adaptor.addMapping("2", radio2);
adaptor.addMapping("3", radio3);
binding.addBinding("selected", adaptor);


binding.setDefaultModel(model);

This creates a BindingInfo instance for a model of Type ExampleModel. The property “string1” is bound to the JTextField instance textfield1. The values of the array property “entriesArray” and the collection property “entries” are bound to the JComboBox instances combo1 and combo2. The property “selected” is bound to three RadioButtons, which are bundled to a group. If radio1 is selected, the value “1” is stored in the “selected” property of the model and so forth.

The model is written to the UI with the following code:

// Initialize the view !
// This also forces the collection to model mapping to be initialized !
binding.model2view();

The state of the UI is written back to the model with the following code:

// Transfer the data to the model
binding.view2model();

Using Mogwai Databinding, you can easily create user interfaces, bind them to POJOs and automate the time consuming and error prone task of copying and converting Java properties.

Git revision: 2e692ad