Simple MVC desktop example wanted
Hi,
I've been looking and can't find a good example of MVC in a desktop application. I don't mean MVC as it is used in component development (I've seen some examples relating to Swing and Buttonmodels, for instance), but more business-object level. I'm not a Java or Swing expert, but I have been programming for a while and and am pretty comfortable writing non-UI Java classes and simple Swing apps. But I want to know how to do this right.
Here's the simplest example I can think of to explain my confusion:
Suppose I have a class called Customer with fields FirstName and LastName. Suppose further I want to create a desktop GUI that allows the customer to edit that model in two separate windows in such a way that changes in one edit window are immediately reflected in the other, and I want clean separation of presentation and logic.
The example doesn't have to be in Swing, but it shouldn't require a server.
Thanks for any help you can give on this - and, if this isn't the right place to post this query, I'd appreciate a pointer to a more appropriate forum.
[1116 byte] By [
WarrenSa] at [2007-10-2 8:20:05]

There are many ways but here is a simple example of how I do it.
******************************* CustomerModel.java
import java.beans.PropertyChangeSupport;
import java.beans.PropertyChangeListener;
/** */
public class CustomerModel
{
/** Change Support Object */
private PropertyChangeSupport propertyChangeSupport = new PropertyChangeSupport(this);
/** bound property names */
public static final String FIRST_NAME_CHANGED = "firstname";
public static final String LAST_NAME_CHANGED = "lastname";
/** First Name Element */
private String firstName;
/** Last Name Element */
private String lastName;
/** Blank Constructor */
public CustomerModel()
{
super();
}
/**
* Sets the first name element. If value changed a notification is
* sent to all listeners of this property
* @param newFirstName String
*/
public void setFirstName(String newFirstName)
{
String oldFirstName = this.firstName;
this.firstName = newFirstName;
propertyChangeSupport.firePropertyChange(FIRST_NAME_CHANGED, oldFirstName, newFirstName);
}
/**
* @return String
*/
public String getFristName()
{
return firstName;
}
/**
* Sets the last name element. If value changed a notification is
* sent to all listeners of this property
* @param newFirstName String
*/
public void setLastName(String newLastName)
{
String oldLastName = this.lastName;
this.lastName = newLastName;
propertyChangeSupport.firePropertyChange(LAST_NAME_CHANGED, oldLastName, newLastName);
}
/**
* @return String
*/
public String getLastName()
{
return lastName;
}
/** Passthrough method for property change listener */
public void addPropertyChangeListener(String str, PropertyChangeListener pcl)
{
propertyChangeSupport.addPropertyChangeListener(str, pcl);
}
/** Passthrough method for property change listener */
public void removePropertyChangeListener(String str, PropertyChangeListener pcl)
{
propertyChangeSupport.removePropertyChangeListener(str, pcl);
}
}
******************************* CustomerFrame.java
import javax.swing.*;
import java.awt.event.*;
import java.awt.GridLayout;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeEvent;
/** */
public class CustomerFrame extends JFrame implements ActionListener, PropertyChangeListener
{
/** Customer to view/control */
private CustomerModel customer;
/** */
private JLabel firstNameLabel = new JLabel("First Name: ");
/** */
private JTextField firstNameEdit = new JTextField();
/** */
private JLabel lastNameLabel = new JLabel("Last Name: ");
/** */
private JTextField lastNameEdit = new JTextField();
/** */
private JButton updateButton = new JButton("Update");
/**
* Constructor that takes a model
* @param customer CustomerModel
*/
public CustomerFrame(CustomerModel customer)
{
// setup this frame
this.setName("Customer Editor");
this.setTitle("Customer Editor");
this.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
this.getContentPane().setLayout(new GridLayout(3, 2));
this.getContentPane().add(firstNameLabel);
this.getContentPane().add(firstNameEdit);
this.getContentPane().add(lastNameLabel);
this.getContentPane().add(lastNameEdit);
this.getContentPane().add(updateButton);
// reference the customer locally
this.customer = customer;
// register change listeners
this.customer.addPropertyChangeListener(CustomerModel.FIRST_NAME_CHANGED, this);
this.customer.addPropertyChangeListener(CustomerModel.LAST_NAME_CHANGED, this);
// setup the initial value with values from the model
firstNameEdit.setText(customer.getFristName());
lastNameEdit.setText(customer.getLastName());
// cause the update button to do something
updateButton.addActionListener(this);
// now display everything
this.pack();
this.setVisible(true);
}
/**
* Update the model when update button is clicked
* @param e ActionEvent
*/
public void actionPerformed(ActionEvent e)
{
customer.setFirstName(firstNameEdit.getText());
customer.setLastName(lastNameEdit.getText());
System.out.println("Update Clicked " + e);
}
/**
* Update the view when the model has changed
* @param evt PropertyChangeEvent
*/
public void propertyChange(PropertyChangeEvent evt)
{
if (evt.getPropertyName().equals(CustomerModel.FIRST_NAME_CHANGED))
{
firstNameEdit.setText((String)evt.getNewValue());
}
else if (evt.getPropertyName().equals(CustomerModel.LAST_NAME_CHANGED))
{
lastNameEdit.setText((String)evt.getNewValue());
}
}
}
******************************* MainFrame.java
import javax.swing.JFrame;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import javax.swing.JButton;
/** */
public class MainFrame extends JFrame implements ActionListener
{
/** Single customer model to send to all spawned frames */
private CustomerModel model = new CustomerModel();
/** Button to click to spawn new frames */
private JButton newEditorButton = new JButton("New Editor");
/** Blank Constructor */
public MainFrame() {
super();
}
/** Create and display the GUI */
public void createAndDisplayGUI()
{
this.setName("MVC Spawner");
this.setTitle("MVC Spawner");
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.newEditorButton.addActionListener(this);
this.getContentPane().add(newEditorButton);
this.pack();
this.setVisible(true);
}
/** Do something when the button is clicked */
public void actionPerformed(ActionEvent e)
{
new CustomerFrame(model);
}
/**
* Creates the main frame to spawn customer edit frames from.
* @param args String[] ignored
*/
public static void main(String[] args) {
MainFrame mainframe = new MainFrame();
mainframe.createAndDisplayGUI();
}
}