GXT (Ext-GWT): Layout problems with ContentPanel

21,371

Solution 1

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);
            }
        });
}

Solution 2

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

Share:
21,371
Chris Lercher
Author by

Chris Lercher

Real name: Christian Lercher Started programming when I was 7 years old (Basic on C64, then Assembler, later C/C++, and now mostly Java). First Windows experience: ca 1993 (Win 3.11) First Unix experience: 1998 (Solaris, then SuSE Linux, now mostly Debian/Ubuntu and macOS. I'm just as much interested in technical things, as in social topics, and economics. It really depends.

Updated on July 09, 2022

Comments

  • Chris Lercher
    Chris Lercher almost 2 years

    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.)

  • Chris Lercher
    Chris Lercher about 13 years
    Unfortunately, contentPanel.layout() and contentPanel.layout(true) does nothing in my case.
  • Chris Lercher
    Chris Lercher about 13 years
    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.
  • Chris Lercher
    Chris Lercher about 13 years
    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.
  • Swapnil
    Swapnil about 13 years
    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.
  • Chris Lercher
    Chris Lercher about 13 years
    @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?
  • Swapnil
    Swapnil about 13 years
    @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.
  • Chris Lercher
    Chris Lercher about 13 years
    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!
  • Swapnil
    Swapnil about 13 years
    @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 help