GXT (Ext-GWT): Layout problems with ContentPanel
Asked Answered
M

3

6

I have a ContentPanel that fits the entire window. It has a topComponent, a widget in the center, and a bottomComponent.

I'm getting layout problems, when I try to add widgets to the topComponent after the ContentPanel has been rendered once:

public void onModuleLoad() {

    final Viewport viewport = new Viewport();
    viewport.setLayout(new FitLayout());

    final ContentPanel contentPanel = new ContentPanel(new FitLayout());
    contentPanel.setHeaderVisible(false);

    final LayoutContainer topContainer = new LayoutContainer(
            new FlowLayout());

    final Button buttonOne = new Button("Top:One");
    topContainer.add(buttonOne);

    contentPanel.setTopComponent(topContainer);
    contentPanel.add(new Button("Center"));
    contentPanel.setBottomComponent(new Button("Bottom"));

    viewport.add(contentPanel);
    RootPanel.get().add(viewport);

    // Later, add a second button to the topComponent ...
    Scheduler.get().scheduleDeferred(new ScheduledCommand() {
        @Override
        public void execute() {
            final Button buttonTwo = new Button("Top:Two");
            topContainer.add(buttonTwo); // Doesn't show up at first.

            topContainer.layout(); // Now, buttonTwo shows up. But we have
                            // a new problem: the "Bottom" button disappears...

            contentPanel.layout(true); // This doesn't do anything, BTW.
        }
    });
}

One interesting thing about this is, that the layout corrects itself, as soon as I resize the browser window. What can I do to make it re-layout correctly immediately (I've tried adding several layout() calls etc. in several places and combinations, but haven't had any luck so far.)

(I'm using GWT 2.1.1 with GXT 2.2.1.)

Marquise answered 5/4, 2011 at 17:22 Comment(2)
What does "getting layout problems" mean ?Interdictory
@Travis: Like the comments in my code mention: At first buttonTwo doesn't show up. Then, when I call layout(), it does show up. But now the "Bottom" button disappears. As soon as I resize the window manually (even just one pixel), the layout corrects itself, i.e. all buttons show up.Marquise
H
8

This is happening because when you add another component to a FlowLayout it resizes, thus increasing its own height, which pushes the bottom component below the visible area. There is nothing in the code which shrinks the center component, such that the bottom component stays in its original place.

One more thing is that you are using FitLayout for contentPanel which contains 3 components, a FitLayout is used for Containers with only one component inside, which is supposed to fill out its parent.

You need to consider the following:

1) Use RowLayout, which allows a much better control on how components should be laid out

2) Decide on which component are you willing to place a vertical scroll bar, since you are adding components dynamically.

For your current requirement the following code should suffice:

public void onModuleLoad() {
       final Viewport viewport = new Viewport();
       viewport.setLayout(new FitLayout());

//     final ContentPanel contentPanel = new ContentPanel(new FlowLayout());
//     contentPanel.setHeaderVisible(false);

        final LayoutContainer topContainer = new LayoutContainer(
                new FlowLayout());

        final Button buttonOne = new Button("Top:One");
        topContainer.add(buttonOne);
//    contentPanel.setTopComponent(topContainer);
        final LayoutContainer centerPanel = new LayoutContainer(new FitLayout());

        centerPanel.add(new Button("Center"));
//    contentPanel.add(centerPanel);
        final LayoutContainer botPanel = new LayoutContainer(new FlowLayout());
        botPanel.add(new Button("Bottom"));
//      contentPanel.setBottomComponent(botPanel);

        final ContentPanel panel = new ContentPanel();  
        panel.setHeaderVisible(false);  
        panel.setLayout(new RowLayout(Orientation.VERTICAL));    


        panel.add(topContainer, new RowData(1, -1, new Margins(4)));  
        panel.add(centerPanel, new RowData(1, 1, new Margins(0, 4, 0, 4)));  
        panel.add(botPanel, new RowData(1, -1, new Margins(4)));  

        viewport.add(panel, new FlowData(10));  


        RootPanel.get().add(viewport);

        // Later, add a second button to the topComponent ...
        Scheduler.get().scheduleDeferred(new ScheduledCommand() {
            @Override
            public void execute() {
                final Button buttonTwo = new Button("Top:Two");
                topContainer.add(buttonTwo); // Doesn't show up at first.
                panel.layout(true);
            }
        });
}
Hysteresis answered 10/4, 2011 at 18:47 Comment(6)
The FitLayout in my contentPanel only has one child: The center button. The "topComponent" and "bottomComponent" are separate. Well, you changed the code to not use "setTopComponent" and "setBottomComponent" at all - and that works, because it doesn't use the topComponent/bottomComponent feature of ContentPanel. (The temporary solution I implemented to work around the issue is similar to yours.) However, I do want to use the topComponent/bottomComponent feature, because it's used everywhere else in the existing code of the project I'm working on - and the layout should work with it, too.Marquise
In your existing code do you dynamically add widgets to top or bottom components? I am asking this because top and bottom containers do not participate in layout after the contentPanel has been rendered. When you manually resize the browser window, onResize is called and it adjusts the height. One thing that you can try, if you insist on using top and bottom components is to call set size method on the panel, by dynamically getting the height and width.Hysteresis
@Swapnil: In the existing code, adding widgets to top/bottom component wasn't necessary so far. But the GXT documentation doesn't say, that you can't add widgets dynamically there, so it was assumed, that this would work. Now, with our workaround (i.e. no top/bottom component), the styling is a little bit different (plus some other minor issues). The original styling can be imitated manually, but this is not a very clean solution. / I just tried contentPanel.setSize(contentPanel.getWidth(), contentPanel.getHeight()); - doesn't work unfortunately. Any other ideas?Marquise
@Chris You can try getting height and width from the Window class from gwt. If you insist using the topComponent and bottomComponent then center component will have to shrink, try calculating the available height for the center component when you add a widget to top component and shrink the center component. Basically here you will have to take layout in your hands.Hysteresis
I'm accepting your answer, and I'll stick with the workaround we had implemented. Getting top/bottom component to work correctly with variable heights seems to be more complex than anything else. I wish, the GXT documentation had warned us about that limitation. Thanks for your help!Marquise
@Chris, when it comes to gxt, source code is your best friend, i have faced and found solutions to problems by going through the source, i hope my suggestion were of some helpHysteresis
I
1

This is happening because the onRender event of topComponent is being invoked in this statement:

contentPanel.setTopComponent(topContainer);

Then, later, you are adding a component: topContainer.add(buttonTwo);. When you resize the window, the onRender event is triggered, and the button you added shows up. The solution to your problem involves triggering the onRender event for topContainer.

Unfortunately, onRender is protected and therefore you cannot call it directly: http://dev.sencha.com/deploy/gxtdocs/com/extjs/gxt/ui/client/widget/LayoutContainer.html#onRender%28com.google.gwt.user.client.Element,%20int%29

You will want to use fireEvent to trigger this programmatically instead of manually resizing the window: http://dev.sencha.com/deploy/gxtdocs/com/extjs/gxt/ui/client/widget/Component.html#fireEvent%28com.extjs.gxt.ui.client.event.EventType%29

Interdictory answered 8/4, 2011 at 18:1 Comment(1)
How exactly do I fire the event? I tried fireEvent(Events.Render) and fireEvent(Events.Resize), both on contentPanel and topContainer. I also tried it on contentPanel.getBottomComponent(). Didn't work so far.Marquise
D
0

once browser completes rendering the widget it won't render that component again so to do it again we can use contentPanel.layout() or contentPanel.layout(true) it re-renders the widgets as per new layout.

Dinothere answered 6/4, 2011 at 7:29 Comment(1)
Unfortunately, contentPanel.layout() and contentPanel.layout(true) does nothing in my case.Marquise

© 2022 - 2024 — McMap. All rights reserved.