GridLayout with percentage column widths?

Is it possible to use a GridLayout (in a Form) and just have the columns be percentages of the total width?

This doesn’t work, but shows my desired intent:

// Two column grid that fills the width of the page, each column taking up one half the space
layout = new GridLayout(2,5);
layout.setWidth("100%");
layout.setColumnExpandRatio(0, 0.5f);
layout.setColumnExpandRatio(1, 0.5f);

// Three column grid that fills the width of the page, each column taking up 1/3rd the space
layout = new GridLayout(3,5);
layout.setWidth("100%");
layout.setColumnExpandRatio(0, 0.33f);
layout.setColumnExpandRatio(1, 0.34f);
layout.setColumnExpandRatio(2, 0.33f);

// Four column grid that fills the width of the page, each column taking up 1/4th the space
layout = new GridLayout(4,5);
layout.setWidth("100%");
layout.setColumnExpandRatio(0, 0.25f);
layout.setColumnExpandRatio(1, 0.25f);
layout.setColumnExpandRatio(2, 0.25f);
layout.setColumnExpandRatio(3, 0.25f);

With a simple HTML table and td, this would be trivial:

<table width="100%">
<tr>
  <td width="25%">col 0</td>
  <td width="25%">col 1</td>
  <td width="25%">col 2</td>
  <td width="25%">col 3</td>
</tr>
</table>

The GridLayout otherwise is a great fit for me because of the flexibility in adding rows based on my bean, which has variable rows to show.

Thanks for any tips…

I tested out your code and it seemed to work just as you described that you wanted it to work. Can you clarify what exactly goes wrong. I’ve modified the code so much that it is easy visually to see what is going on. I’ve added labels to layouts, a background color to the labels to see their size and spacing between the cells to see the borders of the labels.

I have a 1280px wide gridlayout. In the first grid both labels took 634px. In the second grid it was 415px, 427px, 414px (the 0.34 is evident and then there are some rounding differences) and the third every cell gave evenly 311px width to the labels.

Here’s my code as a whole. It is a fully working app ready to be deployed:

PlaygroundApplication.java

package com.example.playground;

import com.vaadin.Application;
import com.vaadin.ui.*;

public class PlaygroundApplication extends Application {
	private static final long serialVersionUID = 6031735832707957247L;

	@Override
	public void init() {
		VerticalLayout mainLayout = new VerticalLayout();
		mainLayout.setSpacing(true);
		Window mainWindow = new Window("Playground Application", mainLayout);
		Label label = new Label("Hello Vaadin user");
		mainWindow.addComponent(label);
		setMainWindow(mainWindow);
	
		// Two column grid that fills the width of the page, each column taking up one half the space
		GridLayout layout = new GridLayout(2,5);
		layout.setWidth("100%");
		layout.setColumnExpandRatio(0, 0.5f);
		layout.setColumnExpandRatio(1, 0.5f);
		layout.addComponent(new Label("foo"), 0, 0);
		layout.addComponent(new Label("foo"), 1, 0);
		layout.setSpacing(true);
		mainWindow.addComponent(layout);
		// Three column grid that fills the width of the page, each column taking up 1/3rd the space
		layout = new GridLayout(3,5);
		layout.setWidth("100%");
		layout.setColumnExpandRatio(0, 0.33f);
		layout.setColumnExpandRatio(1, 0.34f);
		layout.setColumnExpandRatio(2, 0.33f);
		layout.addComponent(new Label("foo"), 0, 0);
		layout.addComponent(new Label("foo"), 1, 0);
		layout.addComponent(new Label("foo"), 2, 0);
		layout.setSpacing(true);
		mainWindow.addComponent(layout);
		
		// Four column grid that fills the width of the page, each column taking up 1/4th the space
		layout = new GridLayout(4,5);
		layout.setWidth("100%");
		layout.setColumnExpandRatio(0, 0.25f);
		layout.setColumnExpandRatio(1, 0.25f);
		layout.setColumnExpandRatio(2, 0.25f);
		layout.setColumnExpandRatio(3, 0.25f);
		layout.addComponent(new Label("foo"), 0, 0);
		layout.addComponent(new Label("foo"), 1, 0);
		layout.addComponent(new Label("foo"), 2, 0);
		layout.addComponent(new Label("foo"), 3, 0);
		layout.setSpacing(true);
		mainWindow.addComponent(layout);
		
		setTheme("playgroundtheme");
	}
}

styles.css

@import url(../reindeer/styles.css);

.v-gridlayout .v-label{
background:lime
}

Screenshot:

Dom tree of the application:

Thanks for the detailed review and analysis. I think the issue may be that the calculated field sizes when I set the TextFields to width of 100% for their respective columns?

Here’s a screen shot of what I see in a Form that shows the imbalance (not 50% and 50% for the two columns):

Here’s the code sets it up:

layout = new GridLayout(2,5);
layout.setWidth("100%");
layout.setColumnExpandRatio(0, 0.5f);
layout.setColumnExpandRatio(1, 0.5f);
layout.setMargin(false);
layout.setSpacing(true);
setLayout(layout);

The left side EsfName label is in a div that’s 529px:

<div style="overflow: hidden; height: 38px; padding-left: 0pt; padding-top: 0px; position: absolute; left: 0px; top: 60px; width: 529px;">
  <div class="v-caption v-caption-hasdescription" style="[b]
width: 529px;
[/b] margin-left: 0px;">
    <div class="v-captiontext">EsfName</div>
      <div class="v-required-field-indicator">*</div>
      <div style="overflow: hidden; clear: both; width: 0pt; height: 0pt;"></div>
    </div>
  <div style="float: left; margin-left: 0px;">
    <input type="text" tabindex="0" class="v-textfield v-textfield-required" style="width: 521px;">
  </div>
</div>

But the right side Description label is in a div that’s only 400px:

<div style="overflow: hidden; height: 38px; padding-left: 0pt; padding-top: 0px; position: absolute; left: 541px; top: 60px; width: 400px;">
  <div class="v-caption v-caption-hasdescription" style="[b]
width: 400px; 
[/b]margin-left: 0px;">
    <div class="v-captiontext">Description</div>
    <div style="overflow: hidden; clear: both; width: 0pt; height: 0pt;"></div>
  </div>
  <div style="float: left; margin-left: 0px;">
    <input type="text" tabindex="0" class="v-textfield" style="width: 392px;">
   </div>
</div>

I’m not sure how those widths are calculated. In the DefaultFieldFactory.createField the TextFields are constructed like this:

                if (propertyId.equals("esfName")) {
                	TextField tf = (TextField)field;
                    tf.addValidator(new GroupEsfNameValidator(vaadinApp,getCurrentGroupBean()));
                    tf.setRequired(true);
                    tf.setWidth("100%");
                    tf.setCaption(vaadinApp.getMsg("caption.esfName"));
                    tf.setDescription(vaadinApp.getMsg("groupForm.esfName.tooltip"));
                } else if ( propertyId.equals("description") ) {
                	TextField tf = (TextField)field;
                	tf.setNullRepresentation("");
                    tf.setWidth("100%");
                    tf.setCaption(vaadinApp.getMsg("caption.description"));
                    tf.setDescription(vaadinApp.getMsg("tooltip.description"));
                }

What I found is that the uneven div calculations are tied to the TextField’s having 100% width. If I remove the setWidth(“100%”), the TextFields are shown narrow, but the DIVs created both have the same size as expected with the 50% for each column. Unfortunately, they are too narrow and don’t use all the column space they have available to them:

So it somehow has to do with the calculations when the widths are set to 100%. I basically want each column to show as much space as the column allows based on the width of the browser window.

Hi,

is there a solution for this problem? i got the same (wrong) behaviour with my gridlayout…

Hi,

I experienced the same problem. In my case i had 4 columns but the first column is 2x the required expand ration so i just divided the value for column 0 by 2
This seems to work as a workaround

	int defRatio = 100 / (columns * 2);
	// // set the ratios
	for (int x = 0; x <= columns * 2; x++)
	{
		if (x == 0)
			layout.setColumnExpandRatio(x, defRatio / 2);
		else
			layout.setColumnExpandRatio(x, defRatio);
	}

Regards,
e

I’m seeing the same problem in Vaadin 7.1 SNAPSHOT.

If I give two columns both the same resize ratio of 1 or 0.5F, one side is always wider than the other.

Old thread, but: Note that expand ratios apply only to any extra space left after allocating space based on fixed/undefined widths etc. Thus, it is normal that your column widths are different if you have content of different sizes in different columns. While some may argue that this behavior is not ideal, it cannot be changed without breaking numerous existing applications.

If expand ratios do not work correctly when taking the above into account, please
create a ticket
with a minimal sample UI class demonstrating the problem.

I think what some of us “old school web types” might like is a widget that uses a TABLE with TD-based widths and each row is a TR for the grid style layout.

Taking Henri Sara’s explanation as starting point, the following workaround seems to get over this problem which puzzled me for days: put each of the components of the grid into a container, in my case VerticalLayout. Then set the width of the container layouts to 100%. The components of the grid then don’t have any ‘extra spacing’ and the columns line up correctly. Don’t know if this is the correct solution or if there are different solutions in other threads, but I found this to be the most general ‘vaadin’ solution that did not involve css fixes etc.

I think it would be worth some explanation in the manual, unless there is one there which I didn’t see - I’m sure others must have puzzled over this one.