Swing is pretty old. We've developed new technologies since its heyday and those new technologies have brought new best practices. One of those is the ability to bind the UI to a Model or ViewModel object. In my current project, we are using Swing as a UI framework and are attempting to move it from the old to the latest and greatest. One of those includes binding.

This is short and sweet, but you can do simple data binding in Swing pretty easily. What we have done is to create a ViewModel object that the view will render from; this ViewModel object is testable and isolated from the Swing code entirely.

For example, in this very simple application we might have three text boxes and a button. TextBox1 and TextBox2 are integer fields that will be added together when an "Add Them!" button is clicked and the result will be displayed in TextBox3. The resulting ViewModel might look something like this.

public class AdditionViewModel {
  private String first;
  private String second;
  private String total;

  public void setFirst(String value) {
    first = value;
    }
  public void setSecond(String value) {
    second = value;
  }

  public String getFirst() {
    return first;
  }

  public String getSecond() {
    return second;
  }

  public String getTotal() {
    return total;
  }

  public void addThem() {
        total = first + second;
  }
}

This is an incredibly simple class which can have tests written against it very easily. Subsequently, the view code might look something like this.

public class AdditionPanel extends JPanel {
    private final AdditionViewModel model;
    // stuff
    private void setupInnards() {
        final JTextField textBox1 = new JTextField();
    textBox1.setText(model.getFirst());
    textBox1.addActionListener((e) => {
      model.setFirst(textBox1.getText());
    });
    this.add(textBox1);

        final JTextField textBox2 = new JTextField();
    textBox2.setText(model.getFirst());
    textBox2.addActionListener((e) => {
      model.setFirst(textBox2.getText());
    });
    this.add(textBox2);

        final JButton button = new JButton();
        button.setText("Add!");
        button.addActionListener((e) => {
            model.addThem();
            redraw();
    });
    this.add(button);
  }

  private void redraw() {
        this.clear();
    this.setupInnards();
        // alternate method:
    // this.textBox1.setText(model.getFirst());
    // this.textBox2.setText(model.getSecond());
  }
  // more stuff
}

This example would get you a simple form of data binding (unfortunately you still have to manually call redraw.. but there are other ways to get to that which I may talk about in the future). The goal and the win here is to push two different things away from the views: logic (even logic we might consider 'view logic') and state management. I want my view to be as dumb as possible so that my tests involving Swing and stateful situations are reduced to a minimum.