How can I use a ComplexPanel with a GWT ActivityManager

1.6k Views Asked by At

I'm trying to modify the GWT 2.1 HelloMVP example code to use a more complex UI. (I'm not allowed to provide the link due to a two link limit)

My problem is that ActivityManager.setDisplay only accepts objects that implement AcceptsOneWidget. LayoutPanel and other ComplexPanel's don't implement AcceptsOneWidget. The example code uses a SimplePanel instead. But I can't seem to nest complex Widgets within the SimplePanel (they don't display).

I've found a few discussions on this problem:

http://www.google.com/url?sa=D&q=https://stackoverflow.com/questions/5143196/is-there-a-acceptsonewidget-which-also-providesresze-other-than-scrollpanel%3Fanswertab%3Dactive%23tab-top

http://www.google.com/url?sa=D&q=http://www.tempura.org/rants/2010/10/using-layoutpanels-with-gwt-2-1s-activitymanager/

People suggest the solution is to create a subclass of the ComplexPanel I want that implements the AcceptsOneWidget interface. Like so:

public class PanelForView extends LayoutPanel implements AcceptsOneWidget { 
     IsWidget myWidget = null; 

    @Override 
     public void setWidget(IsWidget w) { 
         if (myWidget != w)  { 
             if (myWidget != null) { 
                 remove(myWidget); 
             } 

            if (w != null) { 
                 add(w); 
             } 

            myWidget = w; 
         } 
     } 
} 

This sounds great but it doesn't seem to work for me. Perhaps because I'm using GWT 2.3 instead of 2.1 or 2.2. In my EntryPoint I expect to simply replace the SimplePanel with my new PanelForView class and have the app run as before. Like so:

public class HelloMVP implements EntryPoint { 
    private Place defaultPlace = new HelloPlace("World!"); 
//  private SimplePanel appWidget = new SimplePanel(); // Replace this with PanelForView 
    private PanelForView appWidget = new PanelForView(); // This compiles but doesn't work. 
//  private SimpleLayoutPanel appWidget = new SimpleLayoutPanel(); // This doesn't work either. 

    public void onModuleLoad() { 
        // Create ClientFactory using deferred binding so we can replace with different 
        // impls in gwt.xml 
        ClientFactory clientFactory = GWT.create(ClientFactory.class); 
        EventBus eventBus = clientFactory.getEventBus(); 
        PlaceController placeController = clientFactory.getPlaceController(); 

        // Start ActivityManager for the main widget with our ActivityMapper 
        ActivityMapper activityMapper = new AppActivityMapper(clientFactory); 
        ActivityManager activityManager = new ActivityManager(activityMapper, eventBus); 
        activityManager.setDisplay(appWidget); 

        // Start PlaceHistoryHandler with our PlaceHistoryMapper 
        AppPlaceHistoryMapper historyMapper= GWT.create(AppPlaceHistoryMapper.class); 
        PlaceHistoryHandler historyHandler = new PlaceHistoryHandler(historyMapper); 
        historyHandler.register(placeController, eventBus, defaultPlace); 

        RootPanel.get().add(appWidget); 
        // Goes to place represented on URL or default place 
        historyHandler.handleCurrentHistory(); 
    } 
} 

This compiles fine but when I run it, I see nothing but a blank screen now. Is there something extra I have to do to initialize a ComplexPanel? Am I just misunderstanding something? I've tried adding Widgets and calling setSize to no avail. This is my first GWT project.

Thanks for your time.

Corey

3

There are 3 best solutions below

1
On

Use RootLayoutPanel instead of RootPanel

1
On

You should be able to easily use a SimplePanel (or Composite subclass the implement AcceptsOneWidget). The best way to do this is to Think about the containing widget. You can add a: HTMLPanel, FlowPanel, VerticalPanel, etc into the one widget area of SimplePanel.

However, once you do this, you are bending the intended use of ActivityMapper/AcceptsOneWidget/SimplePanel

You can either create a more complex ui by:

Adding another ActivityMapper (with a different UI region - SimplePanel - which should change from Place to Place) or Adding a Widget area (that doesn't change from Place to Place)

or*

Have your Activity control the more complex view (keep the ActivityMapper.setDisplay widget a SimplePanel - but then have the Activity set an HTMLPanel, VerticalPanel, etc)

A very popular implementation is to keep a SimplePanel as the content area for the ActivityMapper. Then use UiBinder (with HTMLPanel as the top level element)

We can call the UiBinder: "view" and it can have many regions

view.getTopArea() - SimplePanel, view.getLeft() - FlowPanel, view.getNameArea - Anchor/InlineHTML

All of these different elements are wrapped into view which can be a Composite

and then, in your

activity.start(AcceptsOneWidget panel){
 panel.setWidget(view);//insert your complex view into the SimplePanel view
  ...
}
0
On

Ok, so when I was having this problem I was just experimenting with the very simple UI that comes with the sample app.

I also tried keeping the SimplePanel and having the Activity return a HeaderPanel consisting of a label and an image (the second method mentioned in Ashton's Answer). I thought this didn't work. And I saw comments in blogs and forums that seemed to indicate this doesn't work. But once I started actually building up the UI with a DockPanel and nested TabPanel, etc., all of the sudden everything started displaying properly. I don't know why. It was probably a bug in my code I suppose. But I'm on my way now. I don't care to go back and diagnose exactly what went wrong. :)

Thanks for the advice guys!

Corey