How can I use a ComplexPanel with a GWT ActivityManager
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 activit开发者_高级运维yManager = 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
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
...
}
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
Use RootLayoutPanel instead of RootPanel
精彩评论