My favorites | Sign in
Project Home Downloads Wiki Issues Source
Search
for
GettingStarted  
A short introduction to the library.
Featured
Updated Apr 29, 2010 by Bitmei...@gmail.com

Introduction

This is a short introduction to the API, essentially providing a simple 'Hello World'-style application.

Details

The Model-View-Presenter pattern consists of three parts. This API only implements some basic piping for the Presenter part - it doesn't dictate any particular Model or View implementation. However, it does have some simple support for standard GWT widgets, which this example will use.

Importing

We will need to add the jar file to the project's library files, and then add the following into the application's *.gwt.xml file:

<inherits name='net.customware.gwt.presenter.Presenter' />

The Presenter

The first class off the rack is the HelloWorldPresenter. Since we're working with GWT widgets, we'll use the WidgetPresenter for convenience, but you could base it directly on Presenter or BasePresenter, depending on what you need.

public class HelloWorldPresenter extends WidgetPresenter<HelloWorldPresenter.Display> {
  public interface Display extends WidgetDisplay {
    public HasValue<String> getName();

    public HasClickHandlers getGo();
  }

  public static final Place PLACE = new Place("HelloWorld");

  public HelloWorldPresenter( Display display, EventBus eventBus ) {
    super( display, eventBus );
  }


  @Override
  protected void onBind() {
    // 'display' is a final global field containing the
    // Display passed into the constructor.
    display.getGo().addClickHandler( new ClickHandler() {
      public void onClick( ClickEvent event ) {
        Window.alert( "Hello, " + display.getName().getValue() + "!" );
      }
    } );
  }

  @Override
  protected void onUnbind() {
    // Add unbind functionality here for more complex presenters.
  }

  public void refreshDisplay() {
    // This is called when the presenter should pull the latest data
    // from the server, etc. In this case, there is nothing to do.
  }

  public void revealDisplay() {
    // Nothing to do. This is more useful in UI which may be buried
    // in a tab bar, tree, etc.
  }

  /**
   * Returning a place will allow this presenter to automatically trigger
   * when '#HelloWorld' is passed into the browser URL.
   */
  @Override
  public Place getPlace() {
    return PLACE;
  }

  @Override
  protected void onPlaceRequest( PlaceRequest request ) {
    // Grab the 'name' from the request and put it into the 'name' field.
    // This allows a tag of '#HelloWorld;name=Foo' to populate the name field.
    String name = request.getParameter( "name", null );
    if ( name != null )
      display.getName().setValue( name );
  }
}

The View

In this case, the view is a GWT Widget. The main thing is that it has to implement HelloWorldPresenter.Display.

public class HelloWorldPanel extends Composite implements HelloWorldPresenter.Display {
  private final TextBox name;
  private final Button go;

  public HelloWorldPanel() {
    FlowPanel panel = new FlowPanel();
    initWidget( panel );

    panel.add( new Label( "What is your name?" ) );
    name = new TextBox();
    name.setText( "World" );
    panel.add( name );

    go = new Button( "Go" );
    panel.add( go );
  }

  public HasValue getName() {
    return name;
  }

  public HasClickHandlers getGo() {
    return go;
  }

  /**
   * Returns this widget as the {@link WidgetDisplay#asWidget()} value.
   */
  public Widget asWidget() {
    return this;
  }

  public void startProcessing() {
    // Do nothing for the moment.
  } 

  public void stopProcessing() {
    // Do nothing for the moment.
  } 
}

Putting it all together

Pretty simple, really. Now, we just have to hook it all up. In your EntryPoint, put something like this:

public class HelloWorldEntryPoint implements EntryPoint {
  public void onModuleLoad() {
  
    // Build the default event bus
    EventBus eventBus = new DefaultEventBus();

    // Build the display and presenter
    HelloWorldPanel display = new HelloWorldPanel();
    HelloWorldPresenter presenter = new HelloWorldPresenter( display, eventBus );

    // Bind the presenter to the display.
    presenter.bind();

    RootPanel.get().add( presenter.getDisplay().asWidget() );

    // Trigger any passed-in history tokens.
    PlaceManager placeManager = new PlaceManager( eventBus );
    placeManager.fireCurrentPlace();
  }
}

GIN/Guice

This also works great with Google GIN, which is a Google Guice-like API for Direct Injection (DI) in GWT. There is a basic AbstractGinModule subclass called AbstractPresenterModule which provides some helper methods for binding Presentation/Display classes easily. There is still some improvement to be made, such as automatically registering the PlaceManager and DefaultEventBus, which for the moment you will have to configure yourself.

Comment by norman.m...@gmail.com, Jul 28, 2009

Is there something missing ? I don't see how the "name" parameter is stored into the History via addItem. Or I'm not understanding it right ?

Comment by forbes...@gmail.com, Aug 5, 2009

I used GWT 1.7. I'm not sure if this caused any problems, but I had to change your example to get it to compile:

In HelloWorldPresenter?.java

void onClick(ClickEvent? event) {

to

public void onClick(ClickEvent? event) {

In HelloWorldPanel?.java

name = new TextBox?("World");

to

name = new TextBox?(); name.setText("World");

Add two methods.

public void startProcessing() {
throw new UnsupportedOperationException?("Not supported yet.");
}
public void stopProcessing() {
throw new UnsupportedOperationException?("Not supported yet.");
}
Comment by forbes...@gmail.com, Aug 7, 2009

In Apache Labs, the Hupa project (GWT based Webmail for IMAP-Servers), has implemented this framework.

http://svn.apache.org/repos/asf/labs/hupa/

I still need to try out a few more things to get my head around all the details.

Comment by djb.b...@gmail.com, Aug 7, 2009

I'm currently implementing this for one of our internal systems. Still on the learning curve :)

Nice work.

Comment by djb.b...@gmail.com, Aug 7, 2009

The gwt-mvp-sample project has implemented this in a branch in svn. Is a good example of how to use this.

Comment by thebrave...@gmail.com, Aug 8, 2009

Im in the same boat as norman.maurer. Can we get some Javadocs up so that we can at least see more details about what we are trying to use?

Comment by brendanp...@gmail.com, Aug 18, 2009

Now, on the client-side, we first need to import the library into our .gwt.xml file. Just add this:

<inherits name='net.customware.gwt.presenter.Presenter' />

Comment by forbes...@gmail.com, Aug 19, 2009

There is another sample application on: http://code.google.com/p/gwt-mvp-sample/source/browse/#svn/branches/gwt-presenter

Get the src code with: svn checkout http://gwt-mvp-sample.googlecode.com/svn/branches/ gwt-mvp-sample-branch

Comment by jpogor...@gmail.com, Aug 22, 2009

This is great. Just want to add my vote for a more complete example.

Comment by olivierh...@gmail.com, Aug 24, 2009

Great work, thank you !

What about remove start/stopProcessing methods from Display and put them in some other interface that extends Display we should call ProcessingDisplay? for instance. DisplayCallback? would have to be modified accordingly.

Comment by project member Bitmei...@gmail.com, Aug 26, 2009

Hi all, I've been lax in checking the comments on this page. I need to figure out how to get comment notifications somehow...RSS feed perhaps? I would suggest posting questions to the Google Group if you want faster responses. Anyway, to answer the questions...

@norman.maurer: The BasicPresenter parent class will automatically add a PlaceRequestHandler into the EventBus for any subclasses that return a Place from getPlace(). It will use the ID for that place (in this case "HelloWorld") to decide whether to trigger the onPlaceRequest method of the Presenter. PlaceManager, at the other end, will listen for History requests and will also listen for PlaceChangedEvents, updating the History with the new value.

@forbes.al: Thanks for the fixes - I've updated the examples. Thanks also for the sample app links and the tutorial link.

@olivierhedin: Separating that out (and the getPlace() method) is probably doable, although it means there will be more 'instanceof' checking in various places. Maybe create a new issue with details of the suggestion.

Comment by markovuk...@gmail.com, Aug 27, 2009

Why do you define Display interface in the presenter itself? in other words why is the display interface nested? Wouldn't it be better if it were not a nested interface?

For example sth like:

interface MyWidgetPresenter? extends BasePresenter?<T extends BaseDisplay?> { .... }

interface Display extends BaseDisplay?<?> { ... }

In my opinion nested interfaces are not that intuitive as interfaces that are not nested.

Comment by project member Bitmei...@gmail.com, Aug 27, 2009

@mark: Mostly it's because that's how Ray defined it in his presentation, so that's where it was to begin with, and I haven't moved it since...

Comment by david.nouls, Aug 28, 2009

I think that putting the Display interface nested in the Presenter makes it clear that the Presenter is the one that mandates the UI to support this interface. It does have the negative effect that you can not have 2 different Presenter implementations - but I guess that in most cases you don't need to. When unit testing (and that is one of the reasons for the pattern) you don't have the need to mock the Presenter with something else, it's the Display implementation that you want to mock.

I must say that the words are a bit confusing. We are always talking about a Model View Presenter pattern... yet the Presenter class is actually the View part and Presenter becomes the Display. so it becomes a MPD pattern! Just a little confusing.

Comment by project member Bitmei...@gmail.com, Aug 28, 2009

Yeah, the terminology does get a little muddy at times. I see it as follows:

  • Model: Data retrieved to be shown/manipulated on screen.
  • View: The actual implementation of the Display
  • Presenter: No responsibility for how the data is displayed, just wires the data to the View (via the Display interface).
Comment by sujaydu...@gmail.com, Oct 10, 2009

Can this be used with SmartGWT?

Comment by project member Bitmei...@gmail.com, Oct 29, 2009

@sujaydutta: I'm not familiar with SmartGWT, but I'm guessing it uses a different 'widget' hierarchy than comes with GWT? If so, it's still possible, you'll just need to create something similar to the WidgetPresenter? and WidgetDisplay? for use with SmartGWT classes. The API itself is not tied to any particular widget implementation.

Comment by grary.st...@gmail.com, Nov 3, 2009

Funny, posted javadoc describes BasicPresenter?<D extents Display> class, but I can't find BasePresenter? class.

Comment by project member Bitmei...@gmail.com, Nov 3, 2009

BasicPresenter? still exists. What version are you using?

Comment by akso...@gmail.com, Nov 28, 2009

What is the best practice to create parametrized presenters/views using Gin and your framework? For example ContactDetails? presenter depends from Contact entity and i can't create it using Provider.get() method from parent presenter.

@AssistedInject? looks what i need, but it doesn't work with Gin. I see two ways - to use factory which seems to be overkill and to set entity via setter after creation (not via constructor). But both ways looks not elegant.

Comment by dusan.ma...@gmail.com, Dec 1, 2009

@aksonov: looking at the gin commit messages, assisted injection should work by now

Comment by bouadma....@gmail.com, Dec 17, 2009

I'm trying gwt-presenter for the first time, trying to see how I'll integrated within my project, first question about the presenter class implemented here :

why PLACE is public static then it's also returned throw the getPlace() methode ?

Comment by project member Bitmei...@gmail.com, Dec 17, 2009

The reason was so that you could create hyperlinks to the location without needing the Presenter instance. However, the 'replace' branch, which will soon become the main trunk, has a new Place API, which does not require Presenter to know about it at all. Instead, you create and register places directly with the PlaceManager? upon construction.

Comment by despine...@gmail.com, Dec 18, 2009

I have a problem with the PlaceManager? implementation. PlaceManager? class implements PlaceRequestHandler?, but it doesn't listen for PlaceRequestEvents? from the EventBus?. Is this a bug? How is PlaceManager?.onPlaceRequest method called?

Comment by kotes...@gmail.com, Feb 23, 2010

Any updates on the replace branch becoming the TRUNK ?

Comment by daniel.s...@gmail.com, Mar 17, 2010

I would really like to find out more about the updates to PlaceManager?...Will there be changes to the API anytime soon?

Comment by flashclo...@gmail.com, Mar 17, 2010

yes,I fund 1.1.1 out in http://borglin.net/gwt-project/?page_id=383,but this place have not any change,why?

Comment by jgon...@gmail.com, Mar 19, 2010

I am also interested on gwt-presenter-1.1.1-replace-SNAPSHOT. Any updates on when will it be available through the maven repository?

Comment by ullenb...@gmail.com, May 21, 2010

After GWT 2.1 now has its own "Place", this framework could be adapted.

Comment by project member Bitmei...@gmail.com, May 21, 2010

Yeah, looks interesting, but I couldn't find any good documentation on the new MVP stuff in GWT 2.1. Any links?

Comment by yadav...@gmail.com, Jul 29, 2010

Where can i find tutorials of GWT "Place"?

Comment by afcoeur@gmail.com, Aug 25, 2010
I am now having trouble compiling my Ginjector derived

class and am receiving the following error.

Rebind result

'net.customware.gwt.presenter.client.place.PlaceManager?' must be a class [

Does anyone know the cause of this?

i use: gwt-dispatch-1.1.0.jar gwt-presenter-1.1.1.jar

many thanks

Comment by rileyl...@gmail.com, Sep 7, 2010

This sample code doesn't seem to compile with gwt-presenter-1.1.1. I get errors on all of the Place instantiations (Place is an abstract class, apparently), and getPlace and onPlaceRequest don't seem to be overrides. Are these changes from 1.0.0?

Comment by Jupp...@gmail.com, Sep 29, 2010

Also, make sure you copy your NEW gwt-servlet.jar to the War/webinf/lib folder. It throws out a bullshit security warning otherwise (missing Serilization Exception). Wow, Im getting this rush of memories, reminding of how much I love(sarcasm) Java.

Comment by project member robert.munteanu, Sep 30, 2010

@Juppie7 : Given that you've expressed your desire to share the new code, if you can provide a link to a short replacement article I would be more than happy to update this page.

Many thanks,

Robert

Comment by iskandar...@gmail.com, Nov 7, 2010

The above tutorial is broken for gwt-presenter 1.1.1

Compile error: Cannot instantiate the type Place

Any fixes?

Comment by intother...@gmail.com, Dec 8, 2010

bad...i had to download 1.0.0 again after 1.1.1 just because sample cant be complied correctly.

Comment by DerrickB...@gmail.com, Jun 10, 2011

in 1.1.1 use DefaultPlaceManager? to create your own version.


Sign in to add a comment
Powered by Google Project Hosting