Vaadin - Responsive Columns - java

I'm new to using Vaadin and have been trying to work out how I can make 2 Components be side by side when at full screen, but then stack on top of each other when the screen is mobile.
My current understanding is that a HorizontalLayout puts things side by side. And a VerticalLayout puts things on top of one another. So how do I go about using the functionality from both?

You need to look into using a different Layout type. Vaadin offers you a CssLayout and CustomLayout as well as the standard Vertical and Horizontal.
My personal favourite at the moment is using a CssLayout and then using a custom CSS Grid to make the components responsive.
Java:
#StyleSheet("MyStyleSheet.css")
public class ResponsiveLayout extends CssLayout {
private static final long serialVersionUID = -1028520275448675976L;
private static final String RESPONSIVE_LAYOUT = "responsive-layout";
private static final String LABEL_ONE = "label-one";
private static final String LABEL_TWO = "label-two";
private Label labelOne = new Label();
private Label labelTwo = new Label();
public ResponsiveLayout() {
config();
addComponents(labelOne, labelTwo);
}
private void config() {
addStyleName(RESPONSIVE_LAYOUT);
labelOne.addStyleName(LABEL_ONE);
labelTwo.addStyleName(LABEL_TWO);
}
}
CSS:
.responsive-layout {
display: grid !important;
grid-template-rows: auto;
grid-template-columns: 1fr 1fr;
display: -ms-grid !important; /* IE */
-ms-grid-rows: auto; /* IE */
-ms-grid-columns: 1fr 1fr; /* IE */
}
.label-one {
grid-column: 1;
-ms-grid-column: 1; /* IE */
}
.label-two {
grid-column: 2;
-ms-grid-column: 2; /* IE */
}
#media all and (max-width : 992px) {
.responsive-layout {
grid-template-columns: 1fr;
-ms-grid-columns: 1fr; /* IE */
}
.label-one {
grid-column: 1;
-ms-grid-column: 1; /* IE */
}
.label-two {
grid-column: 1;
-ms-grid-column: 1; /* IE */
}
}

You can use a Vaadin Add-on responsive layout. Using the grid system of flexboxgrid
#Override
public void enter(ViewChangeListener.ViewChangeEvent event) {
ResponsiveLayout responsiveLayout = new ResponsiveLayout();
responsiveLayout.setSizeFull();
ResponsiveRow rowOne = responsiveLayout.addRow();
Button deleteButton = new Button("", VaadinIcons.TRASH);
deleteButton.addStyleName(ValoTheme.BUTTON_DANGER);
deleteButton.setSizeFull();
Button commentButton = new Button("",VaadinIcons.COMMENT);
commentButton.addStyleName(ValoTheme.BUTTON_PRIMARY);
commentButton.setSizeFull();
Button editButton = new Button("", VaadinIcons.EDIT);
editButton.addStyleName(ValoTheme.BUTTON_FRIENDLY);
editButton.setSizeFull();
rowOne.addColumn().withDisplayRules(12,6,4,4).withComponent(deleteButton);
rowOne.addColumn().withDisplayRules(12,6,4,4).withComponent(commentButton);
rowOne.addColumn().withDisplayRules(12,6,4,4).withComponent(editButton);
ResponsiveRow rowTwo = responsiveLayout.addRow();
Label labelOne = new Label("LABEL 1");
Label labelTwo = new Label("LABEL 2");
rowTwo.addColumn().withDisplayRules(12,6,4,4).withComponent(labelOne);
rowTwo.addColumn().withDisplayRules(12,6,4,4).withComponent(labelTwo);
setSizeFull();
addComponent(responsiveLayout);
}
You can view a basic example here

You can combine your layouts, you might want to put two horizontal layouts within a vertical layout. Think of "boxes within boxes". From there you can fine-tune your layout via css, just analyse the generated HTML.
They had a webinar about layouts some time ago, maybe that helps.

Related

How to reserve space for the VirtualFlow scrollbars?

The current implementation of the VirtualFlow only makes scrollbars visible when view rect becomes less than control size. By control I mean ListView, TreeView and whatever standard virtualized controls. The problem is that vertical scrollbar appearance causes recalculation of the control width, namely it slightly shifts cell content to the left side. This is clearly noticeable and very uncomfortable movement.
I need to reserve some space for the vertical scrollbar beforehand, but none of controls provide API to manipulate VirtualFlow scrollbars behavior, which is very unfortunate API design. Not to mention that most of the implementations place scrollbars on top of the component, thus just overlapping the small part of it.
The question is, "Which is the best way to achieve this?". Paddings won't help, and JavaFX has no margins support. I could put control (e.g ListView) inside of ScrollPane, but I'd bet VirtualFlow won't continue to reuse cells in that case, so it's not a solution.
EXAMPLE:
Expand and collapse node2, it shifts lbRight content.
public class Launcher extends Application {
#Override
public void start(Stage primaryStage) throws Exception {
TreeItem<UUID> root = new TreeItem<>(UUID.randomUUID());
TreeView<UUID> tree = new TreeView<>(root);
tree.setCellFactory(list -> new CustomCell());
TreeItem<UUID> node0 = new TreeItem<>(UUID.randomUUID());
TreeItem<UUID> node1 = new TreeItem<>(UUID.randomUUID());
TreeItem<UUID> node2 = new TreeItem<>(UUID.randomUUID());
IntStream.range(0, 100)
.mapToObj(index -> new TreeItem<>(UUID.randomUUID()))
.forEach(node2.getChildren()::add);
root.getChildren().setAll(node0, node1, node2);
root.setExpanded(true);
node2.setExpanded(true);
BorderPane pane = new BorderPane();
pane.setCenter(tree);
Scene scene = new Scene(pane, 600, 600);
primaryStage.setTitle("Demo");
primaryStage.setScene(scene);
primaryStage.setOnCloseRequest(t -> Platform.exit());
primaryStage.show();
}
static class CustomCell extends TreeCell<UUID> {
public HBox hBox;
public Label lbLeft;
public Label lbRight;
public CustomCell() {
hBox = new HBox();
lbLeft = new Label();
lbRight = new Label();
lbRight.setStyle("-fx-padding: 0 20 0 0");
Region spacer = new Region();
HBox.setHgrow(spacer, Priority.ALWAYS);
hBox.getChildren().setAll(lbLeft, spacer, lbRight);
}
#Override
protected void updateItem(UUID uuid, boolean empty) {
super.updateItem(uuid, empty);
if (empty) {
setGraphic(null);
return;
}
String s = uuid.toString();
lbLeft.setText(s.substring(0, 6));
lbRight.setText(s.substring(6, 12));
setGraphic(hBox);
}
}
}
Reacting to
you can't just extend the VirtualFlow and override a method
certainly true if the method is deeply hidden by package/-private access (but even then: javafx is open source, checkout-edit-compile-distribute is also an option :). In this case we might get along with overriding public api as outlined below (not formally tested!).
VirtualFlow is the "layout" of cells and scrollBars: in particular, it has to cope with handling sizing/locating of all content w/out scrollBars being visible. There are options on how that can be done:
adjust cell width to always fill the viewport, increasing/decreasing when vertical scrollBar is hidden/visible
keep cell width constant such that there is always space left for the scrollBar, be it visible or not
keep cell width constant such that there is never space left the scrollBar, laying it out on top of cell
others ??
Default VirtualFlow implements the first with no option to switch to any other. (might be candidate for an RFE, feel free to report :).
Digging into the code reveals that the final sizing of the cells is done by calling cell.resize(..) (as already noted and exploited in the self-answer) near the end of the layout code. Overriding a custom cell's resize is perfectly valid and a good option .. but not the only one, IMO. An alternative is to
extend VirtualFlow and override layoutChildren to adjust cell width as needed
extend TreeViewSkin to use the custom flow
Example code (requires fx12++):
public static class XVirtualFlow<I extends IndexedCell> extends VirtualFlow<I> {
#Override
protected void layoutChildren() {
super.layoutChildren();
fitCellWidths();
}
/**
* Resizes cell width to accomodate for invisible vbar.
*/
private void fitCellWidths() {
if (!isVertical() || getVbar().isVisible()) return;
double width = getWidth() - getVbar().getWidth();
for (I cell : getCells()) {
cell.resize(width, cell.getHeight());
}
}
}
public static class XTreeViewSkin<T> extends TreeViewSkin<T>{
public XTreeViewSkin(TreeView<T> control) {
super(control);
}
#Override
protected VirtualFlow<TreeCell<T>> createVirtualFlow() {
return new XVirtualFlow<>();
}
}
On-the-fly usage:
TreeView<UUID> tree = new TreeView<>(root) {
#Override
protected Skin<?> createDefaultSkin() {
return new XTreeViewSkin<>(this);
}
};
Ok, this is summary based on #kleopatra comments and OpenJFX code exploration. There will be no code to solve the problem, but still maybe it will spare some time to someone.
As being said, it's VirtualFlow responsibility to manage virtualized control viewport size. All magic happens in the layoutChildren(). First it computes scrollbars visibility and then recalculates size of all children based on that knowledge. Here is the code which causes the problem.
Since all implementation details are private or package-private, you can't just extend the VirtualFlow and override method or two, you have to copy-paste and edit entire class (to remove one line, yes). Given that, changing internal components layout could be a better option.
Sometimes, I adore languages those have no encapsulation.
UPDATE:
I've solved the problem. There is no way no reserve space for vertical scrollbar without tweaking JavaFX internals, but we can limit cell width, so it would be always less than TreeView (or List View) width. Here is simple example.
public class Launcher extends Application {
public static final double SCENE_WIDTH = 500;
#Override
public void start(Stage primaryStage) {
TreeItem<UUID> root = new TreeItem<>(UUID.randomUUID());
TreeView<UUID> tree = new TreeView<>(root);
tree.setCellFactory(list -> new CustomCell(SCENE_WIDTH));
TreeItem<UUID> node0 = new TreeItem<>(UUID.randomUUID());
TreeItem<UUID> node1 = new TreeItem<>(UUID.randomUUID());
TreeItem<UUID> node2 = new TreeItem<>(UUID.randomUUID());
IntStream.range(0, 100)
.mapToObj(index -> new TreeItem<>(UUID.randomUUID()))
.forEach(node2.getChildren()::add);
root.getChildren().setAll(node0, node1, node2);
root.setExpanded(true);
node2.setExpanded(true);
BorderPane pane = new BorderPane();
pane.setCenter(tree);
Scene scene = new Scene(pane, SCENE_WIDTH, 600);
primaryStage.setTitle("Demo");
primaryStage.setScene(scene);
primaryStage.setOnCloseRequest(t -> Platform.exit());
primaryStage.show();
}
static class CustomCell extends TreeCell<UUID> {
public static final double RIGHT_PADDING = 40;
/*
this value depends on tree disclosure node width
in my case it's enforced via CSS, so I always know exact
value of this padding
*/
public static final double INDENT_PADDING = 14;
public HBox hBox;
public Label lbLeft;
public Label lbRight;
public double maxWidth;
public CustomCell(double maxWidth) {
this.maxWidth = maxWidth;
hBox = new HBox();
lbLeft = new Label();
lbRight = new Label();
lbRight.setPadding(new Insets(0, RIGHT_PADDING, 0, 0));
Region spacer = new Region();
HBox.setHgrow(spacer, Priority.ALWAYS);
hBox.getChildren().setAll(lbLeft, spacer, lbRight);
}
#Override
protected void updateItem(UUID uuid, boolean empty) {
super.updateItem(uuid, empty);
if (empty) {
setGraphic(null);
return;
}
String s = uuid.toString();
lbLeft.setText(s.substring(0, 6));
lbRight.setText(s.substring(6, 12));
setGraphic(hBox);
}
#Override
public void resize(double width, double height) {
// enforce item width
double maxCellWidth = getTreeView().getWidth() - RIGHT_PADDING;
double startLevel = getTreeView().isShowRoot() ? 0 : 1;
double itemLevel = getTreeView().getTreeItemLevel(getTreeItem());
if (itemLevel > startLevel) {
maxCellWidth = maxCellWidth - ((itemLevel - startLevel) * INDENT_PADDING);
}
hBox.setPrefWidth(maxCellWidth);
hBox.setMaxWidth(maxCellWidth);
super.resize(width, height);
}
}
}
It's far from perfect, but it works.

How would i add textures to textButtons in libgdx

I'm new to libGDX I've been trying to follow tutorials on how to create buttons and add textures to them however I am really struggling with it. How would I add textures to the continue and back buttons? I only have the png image and a .pack file for the textures
Also if anyone would be able to suggest some ways I can change the font of the labels I have for my buttons e.g. lbl_ip
Any help would be really appreciated.
public class MenuScreen implements Screen {
private Viewport viewport;
private Stage stage;
#SuppressWarnings("unused")
private MainGame game;
private Label lbl_ip;
private Label lbl_name;
private Label lbl_back;
private LabelStyle lbl_style;
private Skin txt_skin;
private TextButtonStyle btn_style;
private TextField txt_ip;
private TextField txt_name;
//private TextField txt_back;
private Button btn_confirm;
private Button btn_back;
public static String ip = "localhost"; // change with user input
public static String name = "Player 1";
public static String back = "<---";
public MenuScreen(MainGame game) {
this.game = game;
viewport = new FitViewport(MainGame.V_WIDTH/6, MainGame.V_HEIGHT/6, new OrthographicCamera());
stage = new Stage(viewport, ((MainGame) game).batch);
lbl_style = new Label.LabelStyle();
lbl_style.font = new BitmapFont();
txt_skin = new Skin(Gdx.files.internal("uiskin.json"));
btn_style = new TextButton.TextButtonStyle();
btn_style.font = new BitmapFont();
Table table = new Table();
table.top();
table.setFillParent(true);
lbl_ip = new Label("please enter an IP address:" , lbl_style);
lbl_name = new Label("enter your name: " , lbl_style);
lbl_back = new Label("Return to Main Menue", lbl_style);
txt_ip = new TextField(ip, txt_skin);
txt_name = new TextField(name, txt_skin);
//txt_back = new TextField(back, txt_skin);
btn_confirm = new TextButton("confirm", btn_style);
btn_back = new TextButton("<--", btn_style);
table.add(lbl_ip).expandX();
table.add(txt_ip).width(200);
table.row();
table.add(lbl_name).expandX();
table.add(txt_name).width(200);
table.row();
//table.add(lbl_back).expandX();
table.add(btn_back);
//table.add(txt_back).width(200);
table.row();
table.add(btn_confirm);
table.row();
stage.addActor(table);
Gdx.input.setInputProcessor(stage);
}
private void buttonHandler() {
if(Gdx.input.isKeyPressed(Input.Keys.ENTER)) {
/*
game.setScreen(new PlayScreen(game));
*/
txt_ip.setTextFieldListener(new TextField.TextFieldListener() {
#Override
public void keyTyped(TextField textField, char c) {
ip = textField.getText();
}
});
txt_name.setTextFieldListener(new TextField.TextFieldListener() {
#Override
public void keyTyped(TextField textField, char c) {
name = textField.getText();
}
});
new MPClient(txt_ip.getText(), txt_name.getText(), game);
dispose();
}
}
#Override
public void show() {
// TODO Auto-generated method stub
}
#Override
public void render(float delta) {
Gdx.gl.glClearColor(0, 0, 0 , 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
stage.draw();
stage.act(delta);
buttonHandler();
}
#Override
public void dispose() {
stage.dispose();
}
}
You need to use ImageTextButton for that. You need to provide it with ImageTextButtonStyle, which is easy to create (you need to assign its imageUp property, other properties can be null).
As far as label font goes, you need to create a new LabelStyle and assign it a new BitmapFont. An example:
Label lab = new Label("This is the text", new LabelStyle(myFont, Color.RED));
"myfont" is a BitmapFont.
Here is a real-world example how to create a BitmapFont:
FreeTypeFontGenerator generator;
FreeTypeFontParameter parameter;
generator = new FreeTypeFontGenerator(Gdx.files.internal("fonts/nidsans-webfont.ttf"));
parameter = new FreeTypeFontParameter();
parameter.size = 12;
parameter.minFilter = TextureFilter.Linear;
parameter.magFilter = TextureFilter.Linear;
myfont = generator.generateFont(parameter);
You need to change the -style- associated with the widget. And you may want to make a new style per widget rather than sharing a style across all (because that would update all widgets with the new background)
LabelStyle newLabelStyle = new LabelStyle(originalLabel.getStyle());
tobeChangedLabel.setStyle(newLabelStyle);
newLabelStyle.background = new Image( //however you like to make the image
Changing the font is somewhat tricky... as the fonts are baked into the style as bitmaps (for rendering speed). You may find that given you don't like the background of your style, or even the font, that you might want to use a different skin. You can make your own or use one from here.
https://github.com/czyzby/gdx-skins
If you have to dynamically choose font you can dynamically build your bitmaps of rendered fonts with gdx-freetype-font-manager
https://jitpack.io/p/1nt3g3r/gdx-freetype-font-manager

JavaFX's Tooltip showDuration doesn't work

I want to display a tooltip inside a TextField when user copies data from it to notify him that it happened and so there is my code.
public class TestController {
#FXML private TextField textField;
private final Clipboard clipboard;
private ContextMenu menu;
private MenuItem menuCopy;
#FXML protected void initialize() {
clipboard = Clipboard.getSystemClipboard();
menu = new ContextMenu();
menuCopy = new MenuItem("Copy");
menuCopy.setOnAction(this::copy);
textField.setContextMenu(menu);
}
private void copy(ActionEvent event) {
final ClipboardContent content = new ClipboardContent();
if(((TextField) menu.getUserData()).getSelectedText().length() == 0)
content.putString(((TextField) menu.getUserData()).getText());
else
content.putString(((TextField) menu.getUserData()).getSelectedText());
clipboard.setContent(content);
Point2D p = ((TextField) menu.getUserData()).localToScreen(0,0);
Tooltip test = new Tooltip("Copied");
test.setShowDuration(new Duration(2000));
test.show(((TextField) menu.getUserData()), p.getX(), p.getY());
}
}
But the setShowDuration doesn't seem to work. It will be displayed forever.
When you install a Tooltip via Tooltip#install(Node,Tooltip)1 there are three event handlers added to the given Node, all related to mouse events. It is these event handlers that implement the showDelay and showDuration functionality. This is done internally by using Timelines. However, when you manually show a Tooltip via one of its show methods you completely bypass this behavior2. In other words, your Tooltip has the same functionality as any other PopupControl.
If you want to manually display a Tooltip and have it disappear after a specified amount of time you'll have to implement that yourself. Here's a proof-of-concept:
import javafx.animation.PauseTransition;
import javafx.scene.control.TextField;
import javafx.scene.control.Tooltip;
import javafx.util.Duration;
public class NotifyingTextField extends TextField {
private final Tooltip tooltip = new Tooltip("Copied contents to clipboard");
private final PauseTransition hideAnimation = new PauseTransition();
{
hideAnimation.durationProperty().bind(tooltip.showDurationProperty());
hideAnimation.setOnFinished(e -> tooltip.hide());
tooltip.setShowDuration(Duration.seconds(2.0));
}
#Override
public void copy() {
var selectedText = getSelectedText();
if (!selectedText.isEmpty()) {
super.copy();
var point = localToScreen(0, 0);
tooltip.show(this, point.getX(), point.getY());
hideAnimation.playFromStart();
}
}
}
Of course, you may be able to find a third-party library that offers a ready-made solution.
1. Even setting properties such as Control#tooltip or Tab#tooltip will delegate to #install(Node,Tooltip).
2. This is true even if the Tooltip is installed. Manually calling show bypasses all the functionality added by the mouse event handlers.
I think it's the way you are implementing it, I tried it and it works for me
PasswordField pf = new PasswordField();
Tooltip tooltip = new Tooltip("Your password must be\nat least 8 characters in length");
tooltip.setShowDuration(new Duration(2000));
pf.setTooltip(tooltip);
If this doesn't work with you try to help us to help you by providing snippet of your code that I can test without adding anything to it

Vaadin Tabsheet undesired refreshing of tab content

I have a Vaadin-TabSheet which has a BrowserFrame in each tab. I notice the following undesired behavior: When I change the tab by clicking on it, the browserframe reloads, possibly erasing any inputs the user might have made in that tab.
How can I keep the tab from reloading? Is there an alternative to the tabSheet?
I now have built my own TabSheet.
I tried to use setVisible on the tab contents, but this also made the browser frame reload. So i came up with the following code to change the size of contents:
private final HorizontalLayout buttons;
private final GridLayout contents;
/**
* Construct a new MyTabSheet
*/
public MyTabSheet() {
buttons = new HorizontalLayout();
contents = new GridLayout();
....
if(t.isSelected()) {
selectedComponent = t.getComponent();
} else {
t.getComponent().setSizeUndefined();
t.getComponent().setWidth(0.0f, Unit.PIXELS);
t.getComponent().setHeight(0.0f, Unit.PIXELS);
}
}
if(null != selectedComponent) {
String frameHeight;
if(selectedComponent instanceof BrowserFrame) {
BrowserFrame bf = (BrowserFrame)selectedComponent;
frameHeight = (String) bf.getData();
} else {
frameHeight = "800px";
}
selectedComponent.setSizeFull();
selectedComponent.setHeight(frameHeight);
}

Vaadin problems with UI size and scrollbar

I'm realitively new to vaadin and I'm struggling with this problems for 2 days now and I'm desperate.
I modified the original addressbook example and it was perfect until that point when I had to expand the ContactForm with another controlls.
It's easier to show what i want to achieve.
It would be good if I could scroll on the right, but I cant. I show what i have already maybe some of you will notice my fault. I wont post all of the code, just the necessary parts.
This is where I create the main layout.
public class VaadinKoliUI extends UI {
#Override
protected void init(VaadinRequest request) {
TabSheet tabsheet = new TabSheet();
HorizontalLayout residentalsTab = new ResidentalsUI();
residentalsTab.setSizeFull();
tabsheet.addTab(residentalsTab,"Lakók");
tabsheet.setSizeFull();
setContent(tabsheet);
}
}
public class ResidentalsUI extends HorizontalLayout implements View{
private Grid residentalsList = new Grid();
ResidentalFormTest residentalForm = new ResidentalFormTest(this);
public ResidentalsUI(){
buildLayout();
}
private void buildLayout(){
HorizontalLayout actions = new HorizontalLayout(filter,excelDownload, newResidental);
actions.setWidth("100%");
filter.setWidth("100%");
actions.setExpandRatio(filter, 1);
VerticalLayout left = new VerticalLayout(actions, getResidentalsList());
left.setSizeFull();
getResidentalsList().setSizeFull();
left.setExpandRatio(getResidentalsList(), 1);
HorizontalLayout mainLayout = new HorizontalLayout(left, residentalForm);
mainLayout.setSizeFull();
mainLayout.setExpandRatio(left, 1);
this.setSizeFull();
this.addComponent(mainLayout);
}
}
public class ResidentalFormTest extends Panel{
FormLayout content = new FormLayout();
Button save = new Button("Save", this::save);
//more buttons and controlls
public ResidentalFormTest(ResidentalsUI rUI) {
this.rUI = rUI;
buildLayout();
}
private void buildLayout() {
this.setSizeUndefined();
content.setMargin(true);
HorizontalLayout actions = new HorizontalLayout(save, cancel);
actions.setSpacing(true);
content.addComponents(actions, name, sex, address, email, phoneNumber, major,classYear,neptunCode,
roomNumber, rfidCode,comment,equipment,equipment1,equipment2);
actions.setSizeUndefined();
this.setContent(content);
}
}
So from what I understood yet, I have to use a Panel because the FormLayout is not capable to show a scrollbar. I should set my root to full with .setSizeFull() and the childs to undefined with .setSizeUndefined() so it would be the size of the browser window and if something is bigger it would show a scrollbar.
If I modify the VaadinKoliUI class as the following I have the scrollbar but the ui shrinks.
public class VaadinKoliUI extends UI {
#Override
protected void init(VaadinRequest request) {
TabSheet tabsheet = new TabSheet();
HorizontalLayout residentalsTab = new ResidentalsUI();
residentalsTab.setSizeUndefined();
tabsheet.addTab(residentalsTab,"Lakók");
tabsheet.setSizeFull();
setContent(tabsheet);
}
}
Like this:
And now I don't know what to do.
But if someone has an easier and quicker idea, to make the ContactForm to scrollable please tell me.
Thanks in advance
Balázs
I should set my root to full with .setSizeFull() and the childs to undefined...
In your case you should see the root as being your Panel and the FormLayout as the child. As per the Vaadin book:
Normally, if a panel has undefined size in a direction, as it has by
default vertically, it will fit the size of the content and grow as
the content grows. However, if it has a fixed or percentual size and
its content becomes too big to fit in the content area, a scroll bar
will appear for the particular direction
The image below is a naive attempt at a visual representation:
This being said, from the moment you modified ResidentalFormTest to extend a Panel and set the FormLayout as it's content, in order to make your panel have a scroll:
set the panel size to 100%, in ResidentalFormTest.buildLayout():
this.setSizeFull()
set the content size to undefined so it can "expand" beyond the panel size: in ResidentalFormTest.buildLayout(): content.setSizeUndefined()
To fix the space allocation between the grid and panel I reckon a 3:1 ratio should suffice. in ResidentalsUI.buildLayout():
mainLayout.setExpandRatio(left, 3);
mainLayout.setExpandRatio(residentalForm, 1);
NOTE: At times it may come in handy to inspect (or experiment with changes) the rendered elements' properties, styles, etc. Some browsers (chrome, firefox) have built-in support for such developer tools, accessible through a menu or a keyboard combination such as CTRL+SHIFT+I
I think you should have
VaadinKoliUI.setSizeFull
ResidentalsUI.setSizeFull
ResidentalsUI.residentalsList.setSizeFull
ResidentalFormTest.setSizeFull
ResidentalFormTest.content.setSizeUndefined
ResidentalsUI.left.setSizeFull
I also suggest to eliminate the HorizontalLayout mainLayout in ResidentalsUI since it is a horizontal layout itself (and if possible to rename it since it isn't a UI and remove the implements View since it does not seem a view).
Your expand ratios looks good, here are the classes I would wrote:
public class VaadinKoliUI extends UI {
#Override
protected void init(VaadinRequest request) {
TabSheet tabsheet = new TabSheet();
ResidentalsLayout residentalsTab = new ResidentalsLayout();
residentalsTab.setSizeFull();
tabsheet.addTab(residentalsTab,"Lakók");
tabsheet.setSizeFull();
setContent(tabsheet);
}
public class ResidentalsLayout extends HorizontalLayout {
private Grid residentalsList = new Grid();
ResidentalFormTest residentalForm = new ResidentalFormTest(this);
public ResidentalsLayout(){
buildLayout();
}
private void buildLayout(){
HorizontalLayout actions = new HorizontalLayout(filter,excelDownload, newResidental);
actions.setWidth("100%");
filter.setWidth("100%");
actions.setExpandRatio(filter, 1);
VerticalLayout left = new VerticalLayout(actions, getResidentalsList());
left.setSizeFull();
residentalsList.setSizeFull();
left.setExpandRatio(residentalsList , 1);
addComponents(left, residentalForm);
setExpandRatio(left, 1);
setSizeFull();
}
}
public class ResidentalFormTest extends Panel {
FormLayout content = new FormLayout();
Button save = new Button("Save", this::save);
//more buttons and controlls
public ResidentalFormTest(ResidentalsLayout rUI) {
this.rUI = rUI;
buildLayout();
}
private void buildLayout() {
setSizeFull();
content.setMargin(true);
HorizontalLayout actions = new HorizontalLayout(save, cancel);
actions.setSpacing(true);
content.addComponents(actions, name, sex, address, email, phoneNumber, major,classYear,neptunCode, roomNumber, rfidCode, comment, equipment, equipment1, equipment2);
content.setSizeUndefined();
setContent(content);
}
}
Let me know if it works as expected.

Categories