How to layout components correctly?

Hi. I’m obviously new to Vaadin as my simple question indicates. I’m trying to understand how to best layout components on screen.

The main screen of the application I’m trying to build is a split panel. The bottom half of the split is a tabbed component while the top half is a series of columns laid out horizontally. I’ve created this layout successfully, but I can’t quite get the hang of how to make the components look correct.

Basically, I’d like the containers in the top and bottom of the split panel to fill to take up the entire space given to them (the idea is that the application, once completed, would be embedded by others into their sites, so I can’t hardcode sizes). And then the tab panel and the columns in each of these containers should also stretch to fill the available area.

I want to control the sizing through CSS, but I’ve failed miserably. I’d fall back to setting it in the code, but that is not ideal, and I have not gotten that to work the way I want either, though I have gotten slightly better results than with CSS alone.

The issue I’m having is that only the split panel is filling the available screen real estate. Everything else is taking up the minimum size instead of also stretching to fill the space, so I end up with a lot of “dead” space.

Here’s the simple code needed to re-create (more or less) what I’m running into:

Stick this in your main application class:

	

		Window aWindow = new Window("test");

		setMainWindow(aWindow);

                SplitPanel aLayout = new SplitPanel(SplitPanel.ORIENTATION_VERTICAL);
		aLayout.setWidth("100%");
		aLayout.setHeight("100%");

		aLayout.setFirstComponent(new Top());
		aLayout.setSecondComponent(new Bottom());

		aWindow.setContent(aLayout);

Now, here is the code for the Top and Bottom classes which represent the column-based component and the tabbed component that i’d like to stretch to fill out the halves of the split panel, but with no luck.


	private class Top extends HorizontalLayout {
		Top() {
			addStyleName("top");

			Panel aOne = new Panel();
			aOne.addStyleName("one");

			Panel aTwo = new Panel();
			aTwo.addStyleName("two");

			Panel aThree = new Panel();
			aThree.addStyleName("three");

			addComponent(aOne);
			addComponent(aTwo);
			addComponent(aThree);
		}
	}

	private class Bottom extends Panel {
		Bottom() {
			addStyleName("bottom");

			TabSheet aTab = new TabSheet();
			aTab.addStyleName("ts");

			Panel aFoo = new Panel();
			aFoo.addStyleName("foo");

			Panel aBar = new Panel();
			aBar.addStyleName("bar");

			Panel aBaz = new Panel();
			aBaz.addStyleName("baz");

			aTab.addTab(aFoo, "foo", null);
			aTab.addTab(aBar, "bar", null);
			aTab.addTab(aBaz, "baz", null);

			setContent(aTab);
		}
	}

Lastly, the CSS. Mostly just to color the components so I can tell them apart and see if they are stretching as I would expect.


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

.v-generated-body {
	/* full height layout does not need scrollable body;
	avoids excess scrollbars if moving sub-window over the window area */
	overflow:hidden;
}

.one, .two, .three {
	width: 100%;
	height: 100%;
	border: black 1px solid;
	background: red;
}

.foo, .bar, .baz {
	width: 100%;
	height: 100%;
	background: green;
}

.top {
	width: 100%;
	height: 100%;
	background: yellow;
}

.bottom {
	width: 100%;
	height: 100%;
	background: blue;
}

.ts {
	width: 100%;
	height: 100%;
}

The intended result is that the tabbed component is the entire size of the bottom half of the split panel, and the components in it’s tab stretch to fill the remaining available area. The top part of the split panel should be filled completely by the three columns.

I would appreciate it if someone could point me at what I’m doing wrong here. I’m sure it’s something simple, but I’m just not seeing it.

Thanks for your time.

SetSizeFull() is your friend!

I’m not exactly sure of every detail you wanted but I guess this will get you at least close to the wanted end result.

To Top, put this at the end of the constructor:

setSizeFull();
aOne.setSizeFull();
aTwo.setSizeFull();
aThree.setSizeFull();

To Bottom, put this at the end of the constructor:

aFoo.setSizeFull();
aBar.setSizeFull();
aBaz.setSizeFull();
setSizeFull();
aTab.setSizeFull();

I just threw setsizefull at everything, as I don’t know the details of the wanted UI. full size equals setWidth(“100%”); and setHeight(“100%”); so you can use those too if you just want to expand the components in one direction.

If you still want to adjust how much one component takes of the layout, say you want aOne to take 50% of Top and aTwo and aThree take 25% each, you can do this at the end of Top:

setExpandRatio(aOne, 2);
setExpandRatio(aTwo, 1);
setExpandRatio(aThree, 1);

PS. I did not take your CSS file to the test, so I don’t know how it looks with it. I used all the way Java with no custom CSS.

Sigh… I must admit we have failed to do this yet, and most component sizes are hard-calculated with JavaScript, without taking CSS sizes into accordance.

You can specify pixel and other fixed-width sizes with CSS (only if you haven’t specified any size in the code), but all relative sizes (percentages) are only appliable from the server-side code.

I hope we’ll fix this in some release, but there’s no plan currently, and if I recall correctly, no ticket even.

Jens, thanks for the help, setSizeFull does indeed work for the top half of the panel, it forces the columns to expand to fill the entire portion of the screen they’re given. They actually expand a little too far by just a pixel or two so you get scroll bars that don’t scroll anything.

I thought setSizeFull was not working for the bottom half of the panel, but then I realized I did not have my setSizeFull calls in the exact order Jens mentioned. Once I re-ordered them, they expanded as expected. What’s the trick to the ordering? The ordering that works was not one I thought was intuitive.

This is a real bummer. It makes it more difficult to create something that I can pass along to other people to embed in their websites and allow them to control sizing, colors, icons, etc. via CSS which was my plan. I’m sure I can get by w/ global constants in one place and get most of the intended joy, but this is unfortunate. So obviously there’s no workaround or planned path forward on this, I’ll humbly suggest that it get added to the roadmap? I’m sure other developers would love this features as well.

If I knew were to look in the Vaadin codebase, I could probably look at this once I was done w/ my current project.

Thanks for the help.

The order does not have any effect. It is just a bunch of “settings” that you specify and they are in fact evaluated upon rendering. It will just render the most outer component first, then work it way inside. That means that your splitpanel size is evaluated first, then the top and bottom, in the bottom the tabsheet is next up, and then the content of the tabs. If you have a wrong size in some outer, it will have an effect on all the inner components. For example if your panel, Bottom, didn’t have the setSizeFull(), everything under it, the tabsheet and the tabs, will not be sized up. Check that you were not missing one of those.

The few pixels over the top, causing you to get scrollbars, may be because of your css. Maybe it is the borders that is pushing them over. The book of Vaadin has some example on how to do borders and margins etc. without breaking the size calculations.

You can do very dynamic and specific layouts that works with many sizes after you get a hang of how to manipulate components on the java side. Best of lucks, and ask more questions if you get stuck!