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.
Related
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.
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);
}
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.
I'm not familiar with css, and unfortunately i dont have much time to investigate this so I've choosen build-in Vaadin ValoTheme.
I have a verticallayout with two objects - label and panel, both components should be centered. This is what i'm trying to archieve:
Unfortunately, after enumorous attempts to make simlar, i got this
My code:
public class SplashScreen extends VerticalLayout implements View {
private static final int PANEL_WIDTH = 320;
private static final int PANEL_HEIGHT = 140;
private static final int BUTTON_WIDTH = 270;
private static final int BUTTON_HEIGHT = 70;
private ComponentHelper componentHelper;
private Panel panel;
private VerticalLayout formLayout;
private Label welcome;
private Button toLoginPage;
public SplashScreen() {
initComponents();
buildSplashView();
}
protected void initComponents() {
componentHelper = ComponentHelper.getInstance();
panel = componentHelper.createPanel("", PANEL_WIDTH, PANEL_HEIGHT);
welcome = componentHelper.createH3Label("Welcome");
formLayout = componentHelper.createVerticalLayout();
toLoginPage = componentHelper.createFriendlyButton("To Login Page", BUTTON_WIDTH, BUTTON_HEIGHT);
toLoginPage.addClickListener(this::redirect);
}
private void buildSplashView() {
addComponent(panel);
addComponent(welcome);
formLayout.addComponent(toLoginPage);
formLayout.setComponentAlignment(toLoginPage, Alignment.MIDDLE_CENTER);
panel.setContent(formLayout);
panel.setStyleName(ValoTheme.PANEL_BORDERLESS);
setComponentAlignment(panel, Alignment.MIDDLE_CENTER);
setHeight(100, Unit.PERCENTAGE);
}
public void redirect(Button.ClickEvent event) {
try {
Thread.sleep(Constants.TRANSITION_TIME_DELAY);
getUI().getNavigator().navigateTo(ViewTokens.SIGNIN);
} catch (InterruptedException e) {
}
}
#Override
public void enter(ViewChangeListener.ViewChangeEvent viewChangeEvent) {
}
}
What i'm doing wrong? I can't fully understand how to design layouts properly( Before asking this question, i read Vaadin Book)
Note: 'componentHelper' intended for object creation with some minimal ValoTheme styling.
Thanks for suggestions
UPDATE: Result of using welcome.setSizeUndefined();
UPDATE 2: modified #qtdzz code to reproduce an issue:
private void buildSplashView() {
addComponent(welcome);
addComponent(text1);
addComponent(panel);
setComponentAlignment(welcome, Alignment.MIDDLE_CENTER);
setComponentAlignment(text1, Alignment.MIDDLE_CENTER);
setComponentAlignment(panel, Alignment.MIDDLE_CENTER);
setSizeFull();
panel.setSizeUndefined();
panel.setContent(formLayout);
welcome.setSizeUndefined();
formLayout.addComponent(toLoginPage);
formLayout.setComponentAlignment(toLoginPage, Alignment.MIDDLE_CENTER);
formLayout.setSizeFull();
}
In my opinion, it will be easier if you put the welcome label inside the formLayout and set alignment for it.
Here is my proposal, hope this help:
private void buildSplashView() {
addComponent(panel);
setComponentAlignment(panel, Alignment.MIDDLE_CENTER);
setSizeFull();
panel.setContent(formLayout);
panel.setStyleName(ValoTheme.PANEL_BORDERLESS);
formLayout.addComponent(welcome);
welcome.setSizeUndefined();
formLayout.addComponent(toLoginPage);
formLayout.setComponentAlignment(toLoginPage, Alignment.MIDDLE_CENTER);
formLayout.setComponentAlignment(welcome, Alignment.MIDDLE_CENTER);
formLayout.setSizeFull();
}
Here is the screenshot for above code:
UPDATE1: Based on your code and according to my understand, one solution could be explained in the following way. If you add "text1", "welcome" and "panel" into it, it will look like the bellow picture:
So to make them align middle center, we need to set expandRatio for "text1" and "panel" to 0.5, and 0 for "welcome". Then make "text1" to be Alignment.BOTTOM_CENTER, "welcome" to be Alignment.MIDDLE_CENTER, "panel" to be Alignment.TOP_CENTER, and the toLoginPage button to be Alignment.TOP_CENTER. Then the view will look like bellow:
Code for above picture:
private void buildSplashView() {
addComponent(text1);
addComponent(welcome);
addComponent(panel);
setComponentAlignment(welcome, Alignment.MIDDLE_CENTER);
setComponentAlignment(text1, Alignment.BOTTOM_CENTER);
setComponentAlignment(panel, Alignment.TOP_CENTER);
setSizeFull();
setExpandRatio(text1,0.5f);
setExpandRatio(panel,0.5f);
panel.setSizeUndefined();
panel.setContent(formLayout);
welcome.setSizeUndefined();
text1.setSizeUndefined();
formLayout.addComponent(toLoginPage);
formLayout.setComponentAlignment(toLoginPage, Alignment.TOP_CENTER);
formLayout.setSizeFull();
}
BTW, I feel that really hard to maintain and understand the solution above (e.g. if you want to add another text, you have to add it between text1 and welcome). My recommend solution is to have one wrapper layout (vertical layout) to wrap all component and set it to be middle_center of the base layout. The solution for this is:
private void buildSplashView() {
wrapperLayout.addComponent(text1);//wrapperLayout is a vertical Layout
wrapperLayout.addComponent(welcome);
wrapperLayout.addComponent(panel);
wrapperLayout.setComponentAlignment(welcome, Alignment.MIDDLE_CENTER);
wrapperLayout.setComponentAlignment(text1, Alignment.MIDDLE_CENTER);
wrapperLayout.setComponentAlignment(panel, Alignment.MIDDLE_CENTER);
addComponent(wrapperLayout);
setComponentAlignment(wrapperLayout, Alignment.MIDDLE_CENTER);
setSizeFull();
panel.setSizeUndefined();
panel.setContent(formLayout);
welcome.setSizeUndefined();
text1.setSizeUndefined();
formLayout.addComponent(toLoginPage);
formLayout.setComponentAlignment(toLoginPage, Alignment.MIDDLE_CENTER);
formLayout.setSizeFull();
}
With this approach, you can add any components into the wrapperLayout, it will be automatically align middle_center.
VerticalLayout outerVLayout = new VerticalLayout();
outerVLayout.setSizeFull();
VerticalLayout innerVLayout = new VerticalLayout();
innerVLayout.setSizeUndefined();
outerVLayout.addComponent(innerVLayout);
outerVLayout.setComponentAlignment(innerVLayout, Alignment.MIDDLE_CENTER);
//add components to this inner vertical layout
innerVLayout.addComponent(label);
//textfields are fine but, in case of a label, remember to do this:
label.setSizeUndefined();
I hope it helps. :-)
I'm working on a SmartGWT project where I'd like my main navigation to be done via a treegrid. The treegrid renders proprerly and its DataSource is functioning appropriately as well. The treegrid is correctly situated to the left of the mainView Canvas.
What I can't seem to figure out is how to switch the contents of the mainView Canvas based on what is selected in the NavigationTree. I've mimicked the functionality I'd like by adding new windows to the existing Canvas, but I can't find an example demonstrating how to clear the canvas entirely and replace it with a new Window.
Am I on the right track here? Can anyone point me at an example that shows roughly what I'm trying to accomplish?
public class NavigationTree extends TreeGrid {
public NavigationTree(Canvas mainView)
{
setDataSource(NavigationDataSource.getInstance());
setAutoFetchData(true);
setShowHeader(false);
addNodeClickHandler(new NavClickHandler(mainView));
}
// Handler for clicking an item on the Navigation Tree.
private class NavClickHandler implements NodeClickHandler
{
private Canvas mainView;
public NavClickHandler(Canvas mainView)
{
super();
this.mainView = mainView;
}
#Override
public void onNodeClick(NodeClickEvent event)
{
Window window = new Window();
window.setWidth(300);
window.setHeight(230);
window.setCanDragReposition(true);
window.setCanDragResize(true);
window.setTitle(event.getNode().getAttribute("name"));
window.addItem(new Label("huzzah!"));
window.setParentElement(mainView);
window.redraw();
}
}
}
You can keep the mainView canvas, clear its children (if any is set) and then set the newly created window as its new child. Something like the following as the body of your click handler:
Window window = new Window();
window.setWidth(300);
window.setHeight(230);
window.setCanDragReposition(true);
window.setCanDragResize(true);
window.setTitle(event.getNode().getAttribute("name"));
window.addItem(new Label("huzzah!"));
for (Canvas child: mainView.getChildren()) {
mainView.removeChild(child);
}
mainView.addChild(window);
I managed to accomplish what I needed with the following change to the event handler code:
public NavClickHandler(UI ui) //UI extends HLayout
{
this.ui = ui;
}
#Override
public void onNodeClick(NodeClickEvent event) {
Window window = new Window();
window.setWidth100();
window.setHeight100();
window.setHeaderControls(HeaderControls.HEADER_LABEL);
window.setTitle(event.getNode().getAttribute("name"));
window.addItem(new Label("Huzzah!"));
ui.setMainView(window);
}
...and the following change to my main UI layout:
public void setMainView(Canvas canvas)
{
mainView.destroy();
mainView = canvas;
addMember(mainView);
this.redraw();
}