Search code examples
layoutcontainersgxt

Sizing Children in a GXT Layout Container


I am trying to create a screen layout that has three sections, the top two of which are a fixed size, and the last of which should expand to fill the remaining space on the screen. I'm using a VerticalLayoutContainer (VLC), which contains three HorizontalLayoutContainers (HLCs). I've attempted to control the size of the HLCs using VerticalLayoutData definitions. I don't want to specify a fixed height for the HLCs because I don't know what they will contain until runtime. The problem that I'm having is that the HLCs are all being placed at position 0,0 in the VLC, and are thus overlaying one another. Here's what this looks like (it's a mess!):

HLCs in a VLC

Here's the UiBinder code that I'm using:

<!DOCTYPE ui:UiBinder SYSTEM 'http://dl.google.com/gwt/DTD/xhtml.ent'>
<ui:UiBinder
  xmlns:gwt='urn:import:com.google.gwt.user.client.ui'
  xmlns:gxtbutton='urn:import:com.sencha.gxt.widget.core.client.button'
  xmlns:gxtcontainer='urn:import:com.sencha.gxt.widget.core.client.container'
  xmlns:gxtform='urn:import:com.sencha.gxt.widget.core.client.form'
  xmlns:gxt='urn:import:com.sencha.gxt.widget.core.client'
  xmlns:ui='urn:ui:com.google.gwt.uibinder'>
  <!-- VerticalLayoutData declarations ========================================================= -->
  <ui:with
    type='com.sencha.gxt.widget.core.client.container.VerticalLayoutContainer.VerticalLayoutData'
    field='fillRemainingLayoutData'>
    <ui:attributes height='1' width='1'/>
  </ui:with>
  <ui:with
    type='com.sencha.gxt.widget.core.client.container.VerticalLayoutContainer.VerticalLayoutData'
    field='sizeToContentsLayoutData'>
    <ui:attributes height='-1' width='1'/>
  </ui:with>
  <!-- ========================================================================================= -->
  <gxtcontainer:Viewport>
    <gxtcontainer:VerticalLayoutContainer>
      <gxtcontainer:child layoutData='{sizeToContentsLayoutData}'>
        <gxtcontainer:HorizontalLayoutContainer>
          <gxtcontainer:VerticalLayoutContainer>
            <gxtform:FieldLabel text='Person.FirstName'/>
          </gxtcontainer:VerticalLayoutContainer>
          <gxtcontainer:VerticalLayoutContainer>
            <gxtform:FieldLabel text='Person.EmailAddress'/>
          </gxtcontainer:VerticalLayoutContainer>
        </gxtcontainer:HorizontalLayoutContainer>
      </gxtcontainer:child>
      <gxtcontainer:child layoutData='{sizeToContentsLayoutData}'>
        <gxtcontainer:HorizontalLayoutContainer>
          <gxtbutton:TextButton text='Save Changes'/>
          <gxtbutton:TextButton text='Undo Changes'/>
        </gxtcontainer:HorizontalLayoutContainer>
      </gxtcontainer:child>
      <gxtcontainer:child layoutData='{fillRemainingLayoutData}'>
        <gxtcontainer:HorizontalLayoutContainer>
          <gxtcontainer:VerticalLayoutContainer>
            <gxtbutton:TextButton text='Organizations'/>
            <gxtbutton:TextButton text='Relationships'/>
          </gxtcontainer:VerticalLayoutContainer>
          <gxtcontainer:CardLayoutContainer>
            <gxt:ContentPanel headerVisible='false'/>
            <gxt:ContentPanel headerVisible='false'/>
          </gxtcontainer:CardLayoutContainer>
        </gxtcontainer:HorizontalLayoutContainer>
      </gxtcontainer:child>
    </gxtcontainer:VerticalLayoutContainer>
  </gxtcontainer:Viewport>
</ui:UiBinder>

And just for completeness, here's the UiBinder Java class:

import com.google.gwt.core.client.GWT;
import com.google.gwt.uibinder.client.UiBinder;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.Widget;

public class PersonDetailsWidget extends Composite {
//==================================================================================================
interface PersonDetailsWidgetUiBinder extends UiBinder<Widget, PersonDetailsWidget> { //
}
//==================================================================================================
public PersonDetailsWidget() {
  final PersonDetailsWidgetUiBinder uiBinder = GWT.create(PersonDetailsWidgetUiBinder.class);
  initWidget(uiBinder.createAndBindUi(this));
}
//--------------------------------------------------------------------------------------------------
}

And here's the entry point class:

import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.user.client.ui.RootLayoutPanel;

public class GXTGrid implements EntryPoint {
//--------------------------------------------------------------------------------------------------
@Override
public void onModuleLoad() {
  final PersonDetailsWidget personDetailsWidget = new PersonDetailsWidget();
  RootLayoutPanel.get().add(personDetailsWidget);
}
//--------------------------------------------------------------------------------------------------
}

I'm very open to any suggestions for alternative/"correct" approaches to this!

** Edit **

After replacing the VerticalLayoutContainer widgets with VBoxLayoutContainer widgets, and the HorizontalLayoutContainer widgets with HBoxLayoutContainer widgets, and removing the layout data entries, the overlap problem is resolved. But now the labels and buttons are truncated. Here's the result:

enter image description here

Note: if I execute a ResizeContainer#forceLayout on the outermost VBoxLayoutContainer then the buttons are all visible; but the field labels are still truncated.


Solution

  • A HorizontalLayoutContainer within a VerticalLayoutContainer has to have a height set. It's just how it works. You should use a HBoxLayoutContainer instead. Here a quick example (without the use of UIBinder):

        VerticalLayoutContainer vlc = new VerticalLayoutContainer();
    
        HBoxLayoutContainer hbc1 = new HBoxLayoutContainer();
        hbc1.add(new Label("Person.FirstName:"));
        hbc1.add(new Label("Person.EmailAddress:"));
        vlc.add(hbc1, new VerticalLayoutData(1, -1));
    
        HBoxLayoutContainer hbc2 = new HBoxLayoutContainer();
        hbc2.add(new TextButton("Save Changes"));
        hbc2.add(new TextButton("Undo Changes"));
        vlc.add(hbc2, new VerticalLayoutData(1, -1));
    

    And that's how it looks like:

    enter image description here