CSS Layout miscalculating height? Sample code provided.

Hi guys.

I have a screen where I was hoping to replace the use of a VerticalLayout with a CssLayout. This knocks a few divs out of the equation, and helps our performance.

This layout exists in a tab, and consists of:

  1. A label (which may or may not exist, and will be of unknown height)
  2. A GridLayout, consisting of several columns, and a potentially large amount of rows.

The label in (1) is to ALWAYS be shown, and the contents of the GridLayout in (2) are to be vertically scrollable as required.

I thought the conversion would be simple, but the CssLayout does not appear to allocate the correct height. The contents of the GridLayout appear to be truncated (and it appears to cut by the height of the static label).

I have attached demo code which shows the problem. You can easily see the last field (field 49) cannot be made fully visible using the scrollbar in the CssLayout when the static label is displayed, but is OK in the VerticalLayout (well, it’s a pixel short but I think thats a Valo thing). Disable the static label however, and the last field can be scrolled to in the CssLayout.

Any ideas? Is it a bug in Vaadin? Note that this problem pre-dates version 7.0 of Vaadin - we’ve always had it. I just thought I’d actually try and track down the problem now!

import com.vaadin.annotations.Theme;
import com.vaadin.data.Property.ValueChangeEvent;
import com.vaadin.data.Property.ValueChangeListener;
import com.vaadin.server.VaadinRequest;
import com.vaadin.ui.AbstractLayout;
import com.vaadin.ui.CheckBox;
import com.vaadin.ui.CssLayout;
import com.vaadin.ui.GridLayout;
import com.vaadin.ui.Label;
import com.vaadin.ui.Panel;
import com.vaadin.ui.TabSheet;
import com.vaadin.ui.TabSheet.Tab;
import com.vaadin.ui.TextField;
import com.vaadin.ui.UI;
import com.vaadin.ui.VerticalLayout;
import com.vaadin.ui.themes.ValoTheme;

@Theme("valo")
public class TestUI extends UI
{       
    private CheckBox cb = null;
    private TabSheet tabSheet = null;
    private Tab cssTab = null;
    private Tab verticalTab = null;
    
    @Override
    public void init(VaadinRequest vaadinRequest)
    {        
        VerticalLayout vl = new VerticalLayout();
        vl.setSizeFull();
        
        cb = new CheckBox("Show static label");
        cb.setSizeUndefined();
        cb.setImmediate(true);
        cb.setValue(false);
        
        cb.addValueChangeListener(new ValueChangeListener()
        {            
            @Override
            public void valueChange(ValueChangeEvent event)
            {
                if (cssTab != null)
                    tabSheet.removeTab(cssTab);
                
                if (verticalTab != null)
                    tabSheet.removeTab(verticalTab);
                
                cssTab = tabSheet.addTab(createLayout(true, cb.getValue()), "Css Layout");
                verticalTab = tabSheet.addTab(createLayout(false, cb.getValue()), "Vertical Layout");              
            }
        });
                
        tabSheet = new TabSheet();
        tabSheet.setSizeFull();
        
        vl.addComponent(cb);
        vl.addComponent(tabSheet);
        vl.setExpandRatio(tabSheet, 1);
        setContent(vl);
        
        cb.setValue(true);                   
    } 
    
    private AbstractLayout createLayout(boolean useCssLayout, boolean showStaticLabel)
    {        
        // create layout to add to the tab sheet
        AbstractLayout layout;
        
        if (useCssLayout)
        {
            layout = new CssLayout();
        }
        else
        {
            layout = new VerticalLayout();
        }
        
        layout.setWidth("100%");
        layout.setHeight("100%");
     
        if (showStaticLabel)
        {
            Label staticLabel = new Label();
            staticLabel.setValue("This is the static label that should not scroll, and always be visible on the user's screen. I have made this intentionally long so that it consumes more than one line, and helps to further highlight the problem I am facing. Your help in this issue is very much appreciated!");        
            layout.addComponent(staticLabel);
        }
        
        // create the actual layout that will hold the fields for this tab            
        GridLayout gl = new GridLayout();
        gl.setColumns(2);        
        gl.setWidth("100%");
        gl.setHeight(null);            
        gl.setMargin(false);
        gl.setSpacing(true);
        gl.setColumnExpandRatio(1, 1);
        
        // 50 rows
        for (int i = 0; i < 50; i++)
        {
            Label label = new Label("Field " + i);
            label.setSizeUndefined();            
            gl.addComponent(label);
            
            TextField textField = new TextField();
            textField.setSizeUndefined();
            gl.addComponent(textField);
        }
                    
        // Panel to wrap layout in, ensuring that we can scroll if required
        Panel panel = new Panel();
        panel.setSizeFull();
        panel.setStyleName(ValoTheme.PANEL_BORDERLESS);            
                    
        // add gridlayout to panel - this is what needs to scroll
        panel.setContent(gl);
                
        // add panel to layout
        layout.addComponent(panel);
        
        // vertical layout? give all expansion to the gridlayout.
        if (!useCssLayout)
        {
            ((VerticalLayout)layout).setExpandRatio(panel, 1);
        }        
         
        return layout;
    }
}

Hi Lee,

There’s no bugs, I’ve checked your code and it works as expected. In CssLayout you just don’t have the expand ratio, so when you say panel.setSizeFull(); your panel will be 100% height of the parent (tab sheet), and thus being pushed by the label downwards offscreen. You can see that the scrollbar goes offscreen as well as you scroll.

You just have to use a VerticalLayout, that’s the reason for its existence, so that it’s posible to do what you want, pure css is not capable of doing this.

Hi.

Thanks very much for your input. Makes perfect sense when you put it like that. VerticalLayout it is then!