Friday, May 2, 2008

Matisse GUI designer - Seperation of Concerns

I like the separation of concern concept and I often use it while creating GUI applications. In Java I use interfaces to achieve separation of concern technique.

Let us explore this concept through an example. We will use NetBeans IDE 6.1 final as editor. The Matisse GUI editor will be used to design the GUI and then keep the generated GUI code separate from the main application logic as much as possible to apply the technique.

Let us assume a small application which will show a window with a text box for the user to type name. We will have two buttons Greet and Close. Greet will show a message with Greetings for the typed name and Close will close the application.

Once we have our expectations set right we can start designing the application and the logic. The main aspect of the separation of concerns concept is to keep the concerns seperate. There is one concern of showing the GUI and receiving user input from that GUI. The second concern is to show the greeting for the received name.

suppose we have a design like:

SimpleWindow as our GUI Frame class
SimpleExample as our main class

I will introduce one interface now
ISimpleListener for disconnecting the GUI from application logic.

I have designed a simple GUI for this application by starting a JFrame form file in NetBeans new file wizard. The design contains a text box and two buttons as we decided.

By double clicking the buttons we can generate the event handlers in the designer. After double clicking the buttons IDE generated the required code for the event handlers. Now we need an interface to notify the events to anyone who will implement the interface.


/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/

package com.company.simpleview;

/**
*
* @author Tushar Joshi
*/
public interface ISimpleListener {

public void close();

public void greet(String text);

}



This can be done by modifying the generated code and by introducing the interface in constructor and keeping a reference in the class.

Then I will call the methods from the interface when the event handlers will be called from GUI.

This is the only change we have to do in the GUI generated class. This is the minimum code we need inside the generated class. Keeping the generated class with minimum custom code will also help me change and regenerate the code again safely.

In the main class SimpleExample now I will use this SimpleWindow class and I will implement the interface so the events notification will be received by my main class and I can write my logic there.


/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package com.company.simpleview;

import com.company.simpleview.gui.SimpleWindow;
import java.awt.EventQueue;
import javax.swing.JOptionPane;

/**
*
* @author Tushar Joshi
*/
public class SimpleExample implements ISimpleListener {

private final SimpleWindow simpleWindow;

public SimpleExample() {
this.simpleWindow = new SimpleWindow(this);
}

public void show() {
EventQueue.invokeLater(new Runnable() {

public void run() {
simpleWindow.setVisible(true);
}
});
}

/**
* @param args the command line arguments
*/
public static void main(String[] args) {
new SimpleExample().show();
}

public void close() {
EventQueue.invokeLater(new Runnable() {

public void run() {
simpleWindow.setVisible(false);
}
});
}

public void greet(String text) {
JOptionPane.showMessageDialog(simpleWindow, text);
}
}



One thing to note here is if I want the GUI in a different way I can change the GUI provided that I dont break the interface and the notifications. The two classes are connected only through this interface to communicate with each other.

This technique is my favorite technique for GUI applications.

with regards
Tushar Joshi, Nagpur

8 comments:

  1. I am intrigued that you chose to have the main class do window things, like invokeLater and popping up panels.

    An alternative is to put this code into your frame class, change your interface to just have a greet method, and have greet return the greetings string.

    Why did you choose the first method?

    ReplyDelete
  2. Hi Howard,

    I wanted to keep thing as simple as I can in this example. My point was to highlight use of the interface ISimpleListener.

    I see your point. There can be many ways to do the things like you said. I could have shifted the methods show() and close() to the SimpleWindow class and just called them from my main class. Now this solution looks better to me. Thanks for the comment.

    One more thing I was trying to achieve is keep the generated class free from custom code as much as I can. Now I wonder why these methods are not automatically generated in the frame class in NetBeans as they are so common things we usually do with the Frame.

    with regards
    Tushar

    ReplyDelete
  3. Why did you use two different names for your main class, SimpleExample in the explanation and SimpleView in the code.
    Thanks!

    ReplyDelete
  4. What if i have another label in SimpleWindow and i want to show the greetings in that label instead in a new JOptionPane. How do you keep things separated in that case?.
    Thanks!

    ReplyDelete
  5. I separate my code from the GUI by making a model class for each GUI class. I make a new model class from the Gui and invoke it's methods for each event. In your way you use three classes instead of two in this way. Could you explain the pros of your way, while considering this way.

    Thanks,
    Shaul

    ReplyDelete
  6. Thanks Ramiro for pointing out one descripency in the example. Earlier I used SimpleView in some places incorrectly now I have updated the post with correction.

    with regards
    Tushar Joshi, Nagpur

    ReplyDelete
  7. >> What if i have another label in
    >> SimpleWindow and i want to show
    >> the greetings in that label
    >> instead in a new JOptionPane. How
    >> do you keep things separated in
    >> that case?.

    Hi Ramiro,
    In this case I will introduce one method in SimpleWindow class so users of this class can set values in the label.

    simpleWindow.setLabel(text);

    I will call this method from the greet event handler in SimpleExample class.

    with regards
    Tushar

    ReplyDelete
  8. Hi Shaul,

    In my example I have highlighted the use of SimpleWindow, the GUI generated class and ISimpleListener one interface to communicate with the GUI.

    Now by using this interface we can implement the GUI from many places and in many ways we want. Using an interface will also enable us to implement it anywhere.

    with regards
    Tushar Joshi, Nagpur

    ReplyDelete