Practicing MVC and disintegrating SWT GUI's

SWT Designer allows you to create the views, editors, perspectives, pref pages, composites, etc. that comprise Eclipse SWT & RCP applications and plug-ins.

Moderators: Konstantin.Scheglov, gnebling, Alexander.Mitin, jwren, Eric Clayberg

Practicing MVC and disintegrating SWT GUI's

Postby Slot Head » Sun Jul 31, 2005 9:33 am

While using SWT-Designer, we are interested in doing two things:
1. Adhering to some form of the Model-View-Controller philosophy.
2. Avoiding the mega GUI from hell syndrome by editing separate panels that are integrated into a larger GUI.

Some of the things that can hinder the above goals seem to be:
1. SWT-Designer makes it so easy to nest composites and build a complex GUI in one .java file.
2. It also provides a super easy way to handle events in the gui.

Complaining about the tool being easy to use is not the purpose of this post.

One approach to MVC we might pursue is to religiously adhere to never writing code in the file that the GUI designer creates. It's obviously the "view" component. A separate controller object would instantiate it, "register" the key widgets, set/get values, add listeners and handle events. This way, if we later decide to redo the GUI in Swing or who knows what, we would toss the old GUI, design a new one and do some relatively simple rewiring of the controller.

As far as disintegrating large GUI's go, we initially figure pushing Composite's out to their own files might be the way to go. Eric explained once where there's good example of this, but I couldn't find it. What are the best practices here?

A goal here for us is to still use the Designer alot and to be able to work fluidly and spontaneously. This might mean not necessarily having a lot of foresight. We'd like to design a GUI as one piece and later, as needed, refactor out some subpanels, but never lose the highly visual, WYSIWYG experience this excellent GUI designer provides. Yes, we're lazy and don't want to write code to make GUI's, which is why we're here. If you have to say "real men write code (or chew holes in punch cards with their bare teeth) to create GUI's," then you already know I am a wimp.

We wonder what obstacles and mutually incompatible aspects might obstruct pursuit of the above two goals. Take, for example, the JFace Dialog class. (BTW, does anybody really find their abstracting the OK and Cancel buttons to be some kind of productivity windfall? I find it often gets in the way when making anything beyond the simplest dialog.) We wonder if this particular class can be harnessed up to the MVC paradigm outlined above, given the way it is implemented. Remember, our goal is to design the GUI visually and then not touch that code ever.

Another aspect we're considering violates some coding practices, or does it? We're thinking about making all the widgets public and have no getters or setters. Heresy! But wait-- before we had OO we had structures. A structure is kinda like an object which has no methods and all its members are public. So that's what we're talking about if you can forgive that there's a couple of methods like createContents. Checking the designer's preferences settings, I don't see a way to configure variables to be public, so we would have to refactor them, which is no big deal, but does make us wonder.

Instantiations has a very cool looking product that does metrics, audits and a bunch of other stuff. There's brief mention of it doing all of the GoF design patterns as well something about GUI. Does our answer lie there? Or, any chance swt-designer might in the future have an MVC code generation option, putting it heads and shoulders above its competition?

All inputs and comments on this topic will be appreciated.

As with some other aspects of using Eclipse/SWT/JFace, I plan on making this into some kind of tutorial or white paper and posting it for review. But I sure hope this will be easier than other things learned the hard way.
Slot Head
 
Posts: 36
Joined: Sun Jul 10, 2005 9:50 am

RE:Practicing MVC and disintegrating SWT GUI's

Postby Sebastien » Tue Aug 09, 2005 5:33 am

I agree with you on the matter of JFace dialogs. Most of the time I have to override createButtonsForButtonBar to get the "handle" on the buttons so I can control them according to validator results for example. And I didn't retain much from the dialog class when I made my custom password-changing dialog even do I extended it.

As for the rest of your post, I will check back from time to time cause your propositions are quite interesting.

Bye
Sebastien
Sebastien
 
Posts: 16
Joined: Thu Jun 02, 2005 12:18 pm
Location: Canada

Postby Slot Head » Tue Aug 09, 2005 8:45 am

Thanks for your post, Sebastien, it's good to find someone else interesting in pursuing MVC. I appreciated hearing your ideas.

A couple of things we learned since:
1. SWT Designer does indeed help make GUI integration easy. One way is this:
a. Do it right from the start. Create a new Composite using File, New, etc. Put widgets and other composites in it.
b. Near the top of the designer's Palette, find the Choose Composite menu item. It lists out the various subpanel composites you've made. Just select one and paste it into the parent GUI. Nice.

If you've built up a large unwiedly GUI, you can still achieve the above. The Extract frame feature may be the way to go, or just copy and paste code to achieve the appraoch described above. E.C. told me Extract frame got broken for a while when SWT/JFace got heavily overhauled, but it works with the latest release.

Also, SWT-Designer provides a function called Expose control which is handy. We use it to create public getters for the widgets that our Controller object will listen to and manipulate.

One problem I foresee with achieving this architecture is with JFace actions. The easy way is to let the designer create a run method stub in the GUI. But that goes against our goal of having the view be dumb and inactive. It may be that we will have to make compromises and let some active code exist in the view layer.
Slot Head
 
Posts: 36
Joined: Sun Jul 10, 2005 9:50 am

Postby Eric Clayberg » Wed Aug 10, 2005 5:53 pm

Slot Head wrote:Near the top of the designer's Palette, find the Choose Composite menu item. It lists out the various subpanel composites you've made. Just select one and paste it into the parent GUI. Nice.

BTW, if you modify and save the composite while also editing a window that uses that composite, the changes to the composite will be reflected in the window as soon as its editor gains focus. You don't need to close and reopen its editor to see the changes in the composite.

Slot Head wrote:SWT-Designer provides a function called Expose control which is handy. We use it to create public getters for the widgets that our Controller object will listen to and manipulate.

There is also a nifty "Expose property" command available for widgets within a composite. This makes it easy to expose specific properties on specific widgets.

Image Image
Eric Clayberg
Software Engineering Manager
Google
http://code.google.com/webtoolkit/download.html

Author: "Eclipse Plug-ins"
http://www.qualityeclipse.com
Eric Clayberg
Moderator
 
Posts: 4503
Joined: Tue Sep 30, 2003 6:39 am
Location: Boston, MA USA

Postby Slot Head » Thu Aug 11, 2005 8:24 am

Thanks Eric. I keep discovering cool features-- or you guys keep adding them. Not sure which.

In our quest for MVC wonderfulness, the thing we are after now is this:
In our Controller class, we want to add selection listeners to Action objects.

The reason we want to do this is because SWT-Designer does such a beautiful job of making GUI design easy with the JFace ApplicationWindow. The abstraction that wires menu items and corresponding tool/cool bar buttons together is a thing of beauty.

As everyone knows, the normal way of coding responses to a JFace Action is with a run method in an anonymous class. For example:
Code: Select all
  actionFileOpen = new Action() {
    public void run() {
       // call some method to open file...
    }
  };


This isn't bad. We could certainly call a handleFileOpen method in our Controller object.

But, what we would really like to do is let the GUI be pretty but dumb. Let it just sit there and not be dynamic. The only methods we'd add to it are public getters so our Controller object can manipulate things and listen for events.

Examining the JFace Action class, we see addPropertyChangeListener but no other add-Listener methods. Bummer. Who made that decision? And why is a newbie like me questioning it?

What we would like to have in Action is an addSelectionListener method.

If we were to extend the Action class to include selection listeners, how hard would it be to still work with SWT-Designer? Is the designer hard coded to look for "Action".

We expect we could use the designer and then hack our code. But, one always wants a round trip ticket, right? We would still want to be able to use the powerful Action editor in the designer. Is this possible?

Another reason we wish to pursue the strategy of "don't put any event handling code in the GUI" is this: If you cut and paste some GUI elements, what happens? You lose the listener code, right? Of course, you could manipulate things just down inside the code, but that partially defeats the purpose of designing GUI's visually.

Am I making sense to anyone? All replies, questions, comments and suggestions will be appreciated.
Slot Head
 
Posts: 36
Joined: Sun Jul 10, 2005 9:50 am

Postby Slot Head » Fri Sep 02, 2005 12:26 pm

To address the issue described in the preceding post in this thread, we are testing a JFace Action wrapper that allows SelectionListener's (or SelectionAdapter's) to be added.

As discussed in preceding posts, the purpose of this is to create MVC architectures with these principles:
1. Never ever write event handling code or any other code in the GUI objects. Only the designer writes code. Use SWT-Designer's Expose control function to allow controllers to access widgets.

2. Create Controller objects that are listeners of widgets in GUI (View) objects. Controllers do all event handling and all moving of data between Views and Models. How stateful controllers should be would be an interesting discussion. In general, keeping state out of them seems like a good idea and all they hold are references to models and views. When state is added, it is GUI-management related, and is not app management related, which belongs in models.

3. Create Model objects that are often just data with getters, setters plus methods to get that data in and out of files, databases, etc. They also contain state machines and other engines. All model objects never talk to the user and are never explicitly aware that view or controller objects exist, though controllers may register themselves as listeners to events coming from models.

In summary:
a. Views (GUI) are pretty but dumb.
b. Models are full of knowledge and muscle.
c. Controllers are busy mediators. They control interaction with the view but do not control the app per se.

This architecture has made our projects far better organized. If we have to rearrange any GUI, its incredibly fast and painless (remember: if you cut and paste widgets in the visual designer, the code you wrote in their event handlers is destroyed).

An important complimentary practice is to design standalone composites. Use File, New, ..., Composite. Put in widgets, use Expose control, set the layout, save the file and don't touch it again. Then, in the parent (yet another composite or the top level window), use SWT-Designer's Choose Composite function. The Designer does a really nice job of showing you the overall design and lets you "drill" down into subpanels using the Open component design function from a context menu. This takes longer to setup but pays off later by keeping all of your gui and related code nicely compartmentalized. It also promotes reuse of gui.

To use the extended Action class, we design a JFace Application window normally using SWT-Designer. Then we delete this line:
Code: Select all
import org.eclipse.jface.action.Action;

and import own extended Action class, shown below.

If you do any JFace Action editing with SWT-Designer, the Designer automatically puts the above regular import back into your code and a compile error occurs, but this is trivial to fix.

Having only a year of Java experience, messing around and extending SWT or JFace is something I do with considerable trepidation. Any/all comments and criticism will be appreciated.


Code: Select all
import java.util.ArrayList;
import java.util.Iterator;

import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.widgets.Event;

public class Action extends org.eclipse.jface.action.Action {
   private ArrayList<SelectionListener> selectionListenerList = new ArrayList<SelectionListener>();

   Action() {
      super();
   }

   Action(String s) {
      super(s);
   }

   public void addSelectionListener(SelectionListener listener) {
      selectionListenerList.add(listener);
   }

   public void removeSelectionListener(SelectionListener listener) {
      selectionListenerList.remove(listener);
   }

   public void runWithEvent(Event event) {
      run();

      Iterator<SelectionListener> iterator = selectionListenerList.listIterator();
      while (iterator.hasNext()) {
         SelectionListener listener = iterator.next();
         SelectionEvent selectionEvent = new SelectionEvent(event);
         listener.widgetSelected(selectionEvent);
      }
   }
}


Happily, we don't have to seriously mess with the JFaceApplication window any further to make things work. We remove or ignore the public static void main(String args[]) method in it and put it in the Controller object instead, having it instatiate the controller which brings up everything else in its constructor as follows:




Code: Select all
   public JFaceAppWindowController(String args[]) {
      // Create any "model" objects here...

      // Create the main window
      window = new JFaceAppWindow();
      window.create();

      createEventHandlers();

      // Open the main window
      window.setBlockOnOpen(true);
      window.open();
      Display.getCurrent().dispose();
   }


There's a few details I haven't described, but will close by briefly mentioning how we do controllers, using the following interface:

Code: Select all
public interface MvcControl {
   public abstract void createEventHandlers();

   public abstract void updateViewFromModel();
   
   public abstract boolean updateModelFromView();   
}
Slot Head
 
Posts: 36
Joined: Sun Jul 10, 2005 9:50 am

Postby pijn_mar » Mon Sep 12, 2005 11:17 pm

This post really got my interest. I'm writing an application, using the excellent SWT-Designer, and my main class is getting bigger and bigger. :oops: So I recognise a lot of what Slot Head mentioned in his starting post.

Is there by any chance a person who can point me to a simple tutorial that shows how to code a GUI application (using eg a few plain SWT widgets) practicing MVC. So not handling events in the gui but in model/controller classes?

I think it is time for this noob to get his project organized before ending up with an unmaintainable application. Any help is appreciated! :D
pijn_mar
 
Posts: 6
Joined: Thu Jun 02, 2005 10:36 pm

Postby jleotta » Wed Sep 14, 2005 12:40 pm

How about:

public Class SWTDesigner extends Composite {

private TextField widget1;
private Table widget2;

public SWTDesigner(){
widget1
widget2
// use expose property option or make widgets public
new Controller(this);
}
}

public Class Controller(){

private SWTDesigner view;

public Controller(SWTDesigner view){
this.view = view;
initializeControls();
}

initializeControls(){
view.getWidget1().doSomethingToIt.
view.getWidget2().doSomethingToIt.
}
}
jleotta
 
Posts: 31
Joined: Tue Aug 03, 2004 9:46 am

Postby bzeiss » Wed Sep 14, 2005 12:43 pm

i'd really like to see something like this implemented in the windowbuilder code generation...
bzeiss
 
Posts: 10
Joined: Wed Jun 01, 2005 2:42 am

Postby jleotta » Wed Sep 14, 2005 12:59 pm

You have the cool option of exposing controls in the SWTDesigner. There is only one line of code to open the controller that you would have to add. The controller is not visual and would be different for everyone so why or even how could it be implemented in the Designer?
jleotta
 
Posts: 31
Joined: Tue Aug 03, 2004 9:46 am

Postby bzeiss » Wed Sep 14, 2005 1:12 pm

good question! the point is that the automatic generation of listeners etc. is not as straight forward with external controllers compared to double clicking the widgets. here an idea:
step 1) windowbuilder should be able to automatically generate a controller skeleton for a visual class. while it does this, it keeps track of which controller can be connected to which visual class
step 2) when a widget is double clicked, a list of possible target controllers is displayed for selection. the according widget is then automatically exposed in the visual class and inside the controller an anonymous listeners class is created for this specific widget.

something like that maybe?
bzeiss
 
Posts: 10
Joined: Wed Jun 01, 2005 2:42 am

Postby jleotta » Wed Sep 14, 2005 1:59 pm

Yes, this would save me some time. Currently I have to add my listeners in the controller. Good idea.
jleotta
 
Posts: 31
Joined: Tue Aug 03, 2004 9:46 am

Postby Slot Head » Wed Sep 14, 2005 4:16 pm

I am delighted to find others who share the idea that we need MVC to organize our GUI apps.

Since early posts we have built several apps using the MVC strategy described and it's working nicely (though it still makes us uneasy that its is quite different than the pattern described in Head First Design Patterns-one of the funnest and best programming books of all time).

We have one app that is like Notepad that I would be happy to zip up and send out. Even better would be to get a wizard like Eric Claybergh to massage and bless it first. If we get a little more serious about this, I'll build a tutorial around it. If not here, there's a website that is gathering such specifically for SWT (http://www.zikal.com). They don't compete with instantiations so I hope it's OK for me to plug them.

For now, here's some ideas, tips and preferences from recent MVC experience:

1. We like to start with a POJO that calls its self AppnameApp. It only has the static main method in it. It's job is to instantiate a class, typically named MainController. This implements the MvcControl interface.

2. The nice thing about starting the above way is this: what if you decide to add a splash screen or do something else before bringing up your main window?

3. MainController creates the MainWindow which was designed by SWT-Designer. It also creates an Object named MainModel where we tend to put all of the "model" stuff, but it doesn't have to be this way.

3b. Note that you have to call create or similarly named method on gui's when they are instantiated or shortly thereafter. The controller classes need to see all the widgets up and instantiated so they can add listeners to handle events.

4. We tend to have one controller per view. A complex main window will consist of various subviews which are discretely designed composites, brought into the mainwindow using Choose Composite. Each of these has its own controller. Every controller tend to have a constructor which passes it references to the parent controller and the view (composite, etc.) that the controller must control.

4. Every controller has a createEventHandlers method that adds listeners with event handling code for all widgets of interest. I think someone mentioned it's a lot easier to let the GUI designer generate the event code, and they're right. Initially we did that, but then transplanted it to controllers.

5. Another tip about generating event handler code: All you need to remember is that you are adding a some kind of listener. For example, just type:
view.getNameOfWidget().addSelectionListener()
Eclipse will want you to put a SelectionListener in as the argument, so you add new SelectionListener(){}
After that Eclipse will complain about unimplemented methods, so hit ctrl+1 to get those.

At this point you're handling the event using a fully built out SelectionListener. But notice that the SWT-Designer people use SelectionAdapter instead. Since this is a class rather than an interface, it allows you to just override the (usually only) one method of interest. So what we do it change "Listener" to "Adapter" after getting the IDE to do most of the coding for us through lots of use of ctrl+space and ctrl+1.

6. Looping. It's really easy to have an event cause a call to updateViewFromMethod. Consequently, a widget gets updated and it fires an event. This leads to another updateViewFromMethod, and there you are in a death loop. In a snap you're out of stack space and the app just goes poof and disappears.

We experiemented with disabling all widgets during updates. This kept them calm and not firing events while they got updated. But we generally don't recommend this approach. One of its problems is that the "focus" is lost- you'd have to save which widget had the focus and then restore it after re-enabling controls.

What we practice now is this: when in an updateViewFromModel routine, plan on updating widgets only if their current value differs from model data. It's a hassle to have to test this and if you know it's not necessary, you can avoid it.

We are toying with the idea of having some sort of flag that says "attention all widgets, do not fire events because you were just hit by code, not the user." Then, if this flag was on, we could simply abort events with event.doit=false.

But, a challenge with this is that this flag's management is not as simple as turning it on and off at the beginning and end of the updateViewFromModel routine. Instead, what is needed is to have it turned off after all the widgets have had a chance to react and have their events aborted. In the world of windows programming we would do a SendMessage at the end of the updateViewFromModel method. We would receive it at just the right time and then switch off the flag.

With SWT, we're not sure how to do this. One hokey idea comes to mind: we could create a phony widget and beat on it at the end of updateViewFromModel. Then, when it's event popped up, we'd know that all the other updated widgets had already happened (unless they send messages to themselves).

Anybody got any ideas on this?

One other idea: whatever we do here, we do not want to prevent being able to do JUnit testing of GUI's. We want our unit tests to be able to bang on buttons and then test if the right thing happened.

7. JFace viewers. The general pattern we've found in developing MVC is that JFace ironically is more hindrance than help. We found the JFace Dialog class to be useless and dumbed down too much. The Action class glaringly lacked the ability to add listeners, so we made a wrapper to fix that. We're now looking at how JFace Viewers work with MVC and getting some mixed results.

The first thing we did was ditch the JFace TableViewer. Our motivation was that we could not find decent descriptions of how its virtual mode works. Anybody want to query 200 million records from a database and call setInput with them in an array? Nope, virtual mode is needed. If anyone's interested, I'll post something or a link to the guys who explain it (the authors of "Definitive Guide to SWT and JFace").

8. With the JFace TreeViewer, however, we are not having MVC problems, so it's a keeper so far. Invariably, we are showing a JDOM object with it, so we've got some label and content provider code that we reuse a lot and would be happy to share. We just put the LabelProvider and ContentPriovider classes into our controller classes. Again, the GUI designer teaches us how. Double click in the Properties editor and it makes nice inner classes for you in the GUI class. Just cut and paste those into the controller class and set them into the viewer there. With this approach, all your gui class has to expose is its viewer object since everything can be done against that.

9. Reusability. Now that were making GUI subpanels, we happily find ourselves reusing them alot. For example, we have a composite that uses the FillLayout and all it has in it is a JFace TreeViewer. Another is like that but only has an SWT table created using SWT.VIRTUAL in its style.

So now we wish we could have more reuse of controller classes. But, our early controllers tended to be very "hard wired" into their surroundings. Subpanel controllers tend to get instantiated with a reference to their parent controller and call back to it to get model information. Sometimes we had subcontrollers reaching back through several layers of parent controllers. This didn't seem right.

We're contemplating a couple of ways to do this. One way would be that the controller would be told by a higher authority where its model resided, When updateViewFromModel was called, it would already have a reference to the model and use it.

The other way is to use interfaces more and give the controller a reference to an object that implements the HasTheStuffIWant interface. We consider this slightly better because it's programming against an interface and allows the holder of the model data to service your request with a method, as opposed to a reference which may no longer be valid.
Slot Head
 
Posts: 36
Joined: Sun Jul 10, 2005 9:50 am

RCP / MVC

Postby matthias.luebken » Fri Dec 16, 2005 7:05 am

After my first couple views, I’ll see my classes getting bigger and bigger and I remembered this thread, so I’ll post my ideas / questions:

We are working with Eclipse-RCP, so our view gets instantiated by Eclipse with the default constructor.

First shot Eclipse-RCP with SWTDesigner and MVC:
- Create a viewpart with SWTDesigner
- Layout your Gui with SWTDesigner and add getters to all controls (use expose control feature from SWTDesigner)
- At the end of the createPartControl-method create an control-object that gets an reference to the viewpart
- Implement a method like createEventHandlers , which is called immediately after creation of the control and hooks to all widgets it wants to listen to

So now I’ve got several disadvantages:
- There is a cyclic dependency between the view and the controller. Usually just the controller knows about the view and not the other way around. But Eclipse creates the viewpart. The only way I see is declaring the Viewpart as the controller, but than I couldn’t use SWTDesigner. :- (
- Right now we have direct calls to specific views. Something like:
[code]IWorkbenchPage activePage = window.getActivePage();
MyViewPart myviewpart = (MyViewPart)activePage.showView(“some.idâ€
matthias.luebken
 
Posts: 9
Joined: Tue Nov 29, 2005 12:55 am


Return to SWT Designer

Who is online

Users browsing this forum: No registered users and 1 guest