Vaadin -layout resizing overlaps - java

Im facing overlaps problem with my project when trying to resize browser.
I was trying so many different variations to make it work, but still result is not acceptable.
Before resizing:
A, B and C are contained in VerticalLayout - I will call it root.
Root is inside HorizontalLayout - content of UI.
A is simple component.
B is extending VerticalLayout that contains 2 HorizontalLayouts inside.
C is only one component - Grid.
Now, when Im trying to resize my browser (like arrow shows) C is starting to steal other components place.
After resizing:
The effect I would like to achieve is that my Grid (C) is not trying to fit my browser. It should not move, and just hide - like below (green is showing actually visible part):
/*ROOT class that extends VerticalLayout*/
private void init()
{
super.setSizeFull();
addA();
addB();
addC();
}
private void addA()
{
Label header = new Label();
super.addComponent(header);
super.setComponentAlignment(header, Alignment.MIDDLE_CENTER);
}
private void addB()
{
layoutB.setSizeFull();
layoutB.setWidth("92%");
super.addComponentsAndExpand(layoutB);
super.setExpandRatio(layoutB, 0.3f);
super.setComponentAlignment(layoutB, Alignment.MIDDLE_CENTER);
}
private void addC()
{
grid.setSizeFull();
grid.setColumnReorderingAllowed(true);
grid.setWidth("92%");
super.addComponentsAndExpand(grid);
super.setExpandRatio(grid, 0.6f);
super.setComponentAlignment(grid, Alignment.BOTTOM_CENTER);
}
As you can see C is added in the same way as B, but only C is moving. Thanks in advance for any help!
Im using Vaadin 8.
#Edit:
#SpringUI(path = "/ui")
public class MyUI extends UI {
#Override
protected void init(VaadinRequest request)
{
Workspace workspace = new Workspace();
HorizontalLayout root = new HorizontalLayout();
root.setSizeFull();
root.addComponentsAndExpand(workspace);
setContent(root);
}
public class Workspace extends Panel
{
public Workspace()
{
init();
}
private void init()
{
setSizeFull();
addStyleName(ValoTheme.PANEL_BORDERLESS);
VerticalLayout layout = new VerticalLayout();
// by default width 100% and height undefined in Vaadin 8
setContent(layout);
// component A
Label label = new Label("Test1");
layout.addComponent(label);
// component B
HorizontalLayout bar = new HorizontalLayout();
bar.addComponents(new Label("Label 1"), new Label("Label 2"));
layout.addComponent(bar);
// component C
Grid<MyBean> grid = new Grid<>(MyBean.class);
grid.setCaption("My Grid:");
grid.setHeight("1000px");
//grid.setHeightByRows(50); // same as fixed height
List<MyBean> items = new LinkedList<>();
IntStream.range(1, 100).forEach(i -> items.add(new MyBean("Item " + i)));
grid.setItems(items);
layout.addComponent(grid);
}
}
public static class MyBean {
private String name;
public MyBean(String name) { this.name = name; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
}
}

Have a look at this working example:
#SpringUI(path = "/ui")
public class MyUI extends UI {
#Override
protected void init(VaadinRequest request) {
Panel panel = new Panel();
panel.addStyleName(ValoTheme.PANEL_BORDERLESS);
panel.setSizeFull();
VerticalLayout layout = new VerticalLayout();
// by default width 100% and height undefined in Vaadin 8
panel.setContent(layout);
// component A
Label label = new Label("Test1");
layout.addComponent(label);
// component B
HorizontalLayout bar = new HorizontalLayout();
bar.addComponents(new Label("Label 1"), new Label("Label 2"));
layout.addComponent(bar);
// component C
Grid<MyBean> grid = new Grid<>(MyBean.class);
grid.setCaption("My Grid:");
grid.setHeight("1000px");
//grid.setHeightByRows(50); // same as fixed height
List<MyBean> items = new LinkedList<>();
IntStream.range(1, 100).forEach(i -> items.add(new MyBean("Item " + i)));
grid.setItems(items);
layout.addComponent(grid);
setContent(panel);
}
public static class MyBean {
private String name;
public MyBean(String name) { this.name = name; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
}
}
The Grid has a fixed height (either by pixels or by number of rows). No expand ratios are necessary for the VerticalLayout. The layout within the Panel will grow as needed by its child components. If the height is greater than the space available for the Panel then scroll bars are shown.

Related

Binding ObjectProperty<Node> to Node's children

I have some ObjectProperty in my class and I don't know how can I bind it to Node's children.
My code:
public class Base extends Parent {
private ObjectProperty<Panel> panel;
private final HBox foundation;
public Base() {
panel = new SimpleObjectProperty<>();
foundation = new HBox(20);
// ???
getChildren().add(foundation);
}
//------Properties below
public final ObjectProperty<Panel> panelProperty() {
return panel;
}
public final void setPanel(Panel value) {
panelProperty().setValue(value);
}
public final Panel getPanel() {
return panelProperty().getValue();
}
}
I want to have an automatic system working like that:
Setting panel property value -> adding the value (node) to foundation's children
EDIT:
I'm talking about adding the node via FXML, like that;
<?xml version="1.0" encoding="UTF-8"?>
<Base xmlns:fx="gui">
<panel>
<Panel/>
</panel>
</Base>
Assuming you just want foundation to contain a single element, which is the current value of panel, just add a listener to panel:
public Base() {
panel = new SimpleObjectProperty<>();
foundation = new HBox(20);
panel.addListener((obs, oldPanel, newPanel) -> {
if (newPanel == null) {
foundation.getChildren().clear();
} else {
// Assumes Panel is a subclass of Node:
foundation.getChildren().setAll(newPanel);
}
});
getChildren().add(foundation);
}
Note that there's no real reason to expose an observable property for panel here, unless you have some other pressing need to actually observe it and respond to changes externally to the class (which seems unlikely). You could simplify the whole thing to:
public class Base extends Parent {
private final HBox foundation;
public Base() {
foundation = new HBox(20);
getChildren().add(foundation);
}
public final void setPanel(Panel value) {
if (value == null) {
foundation.getChildren().clear();
} else {
foundation.getChildren().setAll(value);
}
}
public final Panel getPanel() {
if (foundation.getChildren().isEmpty()) {
return null ;
}
return (Panel) foundation.getChildren().get(0);
}
}

How to set different content for Tabs in Vaadin14?

I have a pretty simple class that basically is just an AppLayout with some Tab.
Now my issue. I am not able to find a smart way to display different contents for the Tabs-class. Is there any interface or something that can be called to differ the content for the Tab?
class MainAppView extends AppLayout {
public MainAppView()
{
createDrawerAndAddToAppView();
}
void createDrawerAndAddToAppView()
{
Tabs tabs = createTabsForDrawer();
tabs.setOrientation(Tabs.Orientation.VERTICAL);
addToDrawer(tabs);
H1 a = new H1("Test"); // Is displayed as content for every Tab
tabs.addSelectedChangeListener(selectedChangeEvent ->
/**
* How to get the specific content of a Tab here?
*/
//selectedChangeEvent.getSelectedTab(). //getContent() and put in super.setContent()?
super.setContent(a)); // Displays 'Test' as content for every Tab
// The Listener shall display the specific content of the getSelectedTab()
}
private Tabs createTabsForDrawer()
{
return new Tabs(
new Tab("Home"),
new Tab("Dummy"),
new Tab("Test"));
}
}
Here is one example, using a map to keep track of which content belongs to which tab. In reality your tab content would be more complicated, and maybe be created in it's own method.
#Route
public class TabTest extends VerticalLayout {
private Map<Tab, Component> tabComponentMap = new LinkedHashMap<>();
public TabTest() {
Tabs tabs = createTabs();
Div contentContainer = new Div();
add(tabs, contentContainer);
tabs.addSelectedChangeListener(e -> {
contentContainer.removeAll();
contentContainer.add(tabComponentMap.get(e.getSelectedTab()));
});
// Set initial content
contentContainer.add(tabComponentMap.get(tabs.getSelectedTab()));
}
private Tabs createTabs() {
tabComponentMap.put(new Tab("Show some text"), new H1("This is the text tab"));
tabComponentMap.put(new Tab("Show a Combo Box"), new ComboBox<String>());
tabComponentMap.put(new Tab("Show a button"), new Button("Click me and nothing happens"));
return new Tabs(tabComponentMap.keySet().toArray(new Tab[]{}));
}
}
You can do something similar with routes also, but then you would probably want your containing component to be a RouterLayout. Also this requires a bit more logic if you want to automatically select the correct tab after navigating from somewhere else.
#Route
public class TabTest extends VerticalLayout implements RouterLayout {
private Map<Tab, String> tabToUrlMap = new LinkedHashMap<>();
private Div contentContainer = new Div();
public TabTest() {
Tabs tabs = createTabs();
Div contentContainer = new Div();
contentContainer.setSizeFull();
add(tabs, contentContainer);
tabs.addSelectedChangeListener(e ->
UI.getCurrent().navigate(tabToUrlMap.get(e.getSelectedTab())));
}
private Tabs createTabs() {
RouteConfiguration routeConfiguration = RouteConfiguration.forApplicationScope();
tabToUrlMap.put(new Tab("View 1"), routeConfiguration.getUrl(TestView1.class));
tabToUrlMap.put(new Tab("View 2"), routeConfiguration.getUrl(TestView2.class));
tabToUrlMap.put(new Tab("View 3"), routeConfiguration.getUrl(TestView3.class));
return new Tabs(tabToUrlMap.keySet().toArray(new Tab[]{}));
}
#Override
public void showRouterLayoutContent(HasElement content) {
getElement().appendChild(content.getElement());
}
}
And an example view
#Route(layout = TabTest.class)
public class TestView3 extends VerticalLayout {
public TestView3() {
add("View 3");
}
}

How to use theme Selected style for Component in ListCellRenderer if isSelected

I have a custom ListCellRenderer in which I would like to have the currently selected item highlighted with a background gradient.
It seems like I should be able to define the Selected style for the rendered component in the Codenameone Designer under theme and set that UIID for the component to achieve this.
I can't figure out how to pass the selected state of the list item to the Label component being rendered though, so I resort to changing the style manually as you can see in my code below. Can I accomplish the same behaviour with my theme Resources somehow?
public class PlanetListRenderer extends Container implements ListCellRenderer<Hashtable<String, String>> {
private Label planetLabel = new Label();
private Resources theme;
public PlanetListRenderer(Resources theme) {
this.theme = theme;
BoxLayout bl = new BoxLayout(BoxLayout.Y_AXIS);
setLayout(bl);
planetLabel.setUIID("PlanetListItem");
planetLabel.setTextPosition(Label.BOTTOM);
addComponent(planetLabel);
}
public Component getListFocusComponent(List list) {
return planetLabel;
}
public Component getListCellRendererComponent(List list,
Hashtable<String, String> value, int index, boolean isSelected) {
planetLabel.setIcon(theme.getImage("icon" + value.get("value") + ".png"));
planetLabel.setText(value.get("value"));
if ( isSelected ) {
planetLabel.getStyle().setBackgroundGradientStartColor(255255255);
planetLabel.getStyle().setBackgroundGradientRelativeY(0.2f);
planetLabel.getStyle().setBackgroundGradientRelativeSize(1.0f);
planetLabel.getStyle().setBackgroundType(Style.BACKGROUND_GRADIENT_RADIAL);
} else {
planetLabel.getStyle().setBackgroundType(Style.BACKGROUND_NONE);
}
return this;
}
}
Below is a ListCellRenderer which changes the selected item. Not sure if it does what you're looking for, but you can see it for real from Google Play (or App Store) by searching for "Torquepower Diesel Cummins Engine" app. When you select any list item you'll see the backgound change.
public class FaultCodesListCellRenderer extends Container implements ListCellRenderer {
Label focus;
Label code;
Label effect;
Image warning;
Image emergency;
public FaultCodesListCellRenderer(Resources res) {
// get images for warning lights
emergency = res.getImage("emergency.png");
warning = res.getImage("warning.png");
setLayout(new BorderLayout());
setUIID("Underline");
code = new Label();
code.setUIID("BoldLabel");
code.setTextPosition(RIGHT);
code.getStyle().setMargin(Component.RIGHT, 6);
effect = new Label();
effect.setTickerEnabled(false);
addComponent(BorderLayout.WEST, code);
addComponent(BorderLayout.CENTER, effect);
int h = Display.getInstance().convertToPixels(8, false);
setPreferredH(code.getPreferredH() < h ? h : code.getPreferredH());
focus = new Label("");
focus.setUIID("UnderlineSelected");
}
public Component getListCellRendererComponent(List list, Object value, int index, boolean isSelected) {
Diagnostic diagnostic = (Diagnostic) value;
if (diagnostic.light.equals("R")) {
code.setIcon(emergency);
} else {
code.setIcon(warning);
}
code.setText(diagnostic.code);
effect.setText(diagnostic.effect);
return this;
}
public Component getListFocusComponent(List list) {
return focus;
}
I suggest using background images/borders instead of gradients which aren't as performant.
By default touch UI's don't show selection permanently. If you use getAllStyles instead of getStyle e.g.:
Form hi = new Form("Renderer Demo", new BorderLayout());
ArrayList<Map<String, String>> al = new ArrayList<>();
for(int iter = 0 ; iter < 100 ; iter++) {
HashMap<String, String> data = new HashMap<String, String>();
data.put("key1", "Data " + iter);
data.put("key2", "Different Data " + iter);
al.add(data);
}
DefaultListModel<Map<String, String>> listModel = new DefaultListModel<>(al);
List<Map<String, String>> l = new List<>(listModel);
l.setRenderer(new ListCellRenderer() {
private Container container;
private Label cover;
private TextArea item;
{
item = new TextArea(2, 80);
cover = new Label();
container = BorderLayout.center(item).add(BorderLayout.EAST, cover);
container.setCellRenderer(true);
cover.setCellRenderer(true);
item.setCellRenderer(true);
}
#Override
public Component getListCellRendererComponent(List list, Object value, int index, boolean isSelected) {
Map<String, String> val = (Map<String, String>)value;
item.setText(val.get("key1"));
cover.setText(val.get("key2"));
Style itemStyle = item.getAllStyles();
Style coverStyle = cover.getAllStyles();
Style containerStyle = container.getAllStyles();
itemStyle.setBgTransparency(255);
coverStyle.setBgTransparency(255);
containerStyle.setBgTransparency(255);
if (isSelected) {
itemStyle.setFgColor(0xff0000);
itemStyle.setBgColor(0x000000);
coverStyle.setBgColor(0xff0000);
containerStyle.setBgColor(0x000000);
} else {
itemStyle.setFgColor(0x000000);
itemStyle.setBgColor(0xffffff);
coverStyle.setBgColor(0x000000);
containerStyle.setBgColor(0xffffff);
}
return container;
}
#Override
public Component getListFocusComponent(List list) {
return null;
}
});
hi.add(BorderLayout.CENTER, l);
hi.show();

Formatting issues in View - Vaadin

I have created a view as below:
The menu Layout or the left vertical layout does not have the entire Layout filled in Blue color. Its only Blue till the respective Buttons are present.
I need to have the entire Menu Layout in Blue Color and retain the Buttons in same position as it is now. So, to achieve it I uncommented the below code in the view
menuLayout.setSizeFull();
But the entire menu layout becomes very bad to look as below. please see the below snapshot
Could someone please help on this?
The code used is as below:
public class AppointmentView extends CustomComponent implements View,Button.ClickListener {
private static final long serialVersionUID = 1L;
public static final String NAME = "Appointment";
private VerticalLayout mainLayout = new VerticalLayout();
private VerticalLayout upperSection = new VerticalLayout();
private HorizontalSplitPanel lowerSection = new HorizontalSplitPanel();
private VerticalLayout menuLayout = new VerticalLayout();
private VerticalLayout contentLayout = new VerticalLayout();
private Button newContact = new NativeButton("Add contact");
private Button search = new NativeButton("Search");
private Button share = new NativeButton("Share");
private Button help = new NativeButton("Help");
private NavigationTree tree = new NavigationTree();
public AppointmentView() {
setSizeFull();
upperSection.addComponent(new Label(""));
menuLayout.addComponent(new Label(""));
contentLayout.addComponent(new Label(""));
menuLayout.setSpacing(true);
//menuLayout.setSizeFull();
menuLayout.setStyleName(Reindeer.LAYOUT_BLUE);
lowerSection.addComponent(menuLayout);
lowerSection.addComponent(contentLayout);
lowerSection.setSizeFull();
upperSection.setStyleName(Reindeer.LAYOUT_BLUE);
upperSection.addComponent(createToolbar());
lowerSection.setSplitPosition(30);
menuLayout.addComponent(createVerticalToolbar());
mainLayout.addComponent(upperSection);
mainLayout.addComponent(lowerSection);
mainLayout.setSizeFull();
mainLayout.setExpandRatio(lowerSection, 1);
setCompositionRoot(mainLayout);
}
private Component createToolbar() {
HorizontalLayout layout = new HorizontalLayout();
Embedded em = new Embedded("", new ClassResource("../../com/image/logo.png"));
layout.addComponent(em);
layout.setComponentAlignment(em, Alignment.MIDDLE_RIGHT);
layout.setExpandRatio(em, 1);
layout.setStyleName("toolbar");
layout.setMargin(true);
layout.setSpacing(true);
layout.setWidth("100%");
return layout;
}
#SuppressWarnings("deprecation")
private Component createVerticalToolbar() {
VerticalLayout lo = new VerticalLayout();
newContact.setStyleName("img");
newContact.setWidth("100%");
newContact.setIcon(new ClassResource("../../com/image/document-add.png"));
newContact.addListener((Button.ClickListener) this);
lo.addComponent(newContact);
search.setIcon(new ClassResource("../../com/image/folder-add.png"));
search.addListener((Button.ClickListener) this);
search.setWidth("100%");
lo.addComponent(search);
share.setIcon(new ClassResource("../../com/image/users.png"));
share.addListener((Button.ClickListener) this);
share.setWidth("100%");
lo.addComponent(share);
help.setIcon(new ClassResource("../../com/image/help.png"));
help.addListener((Button.ClickListener) this);
help.setWidth("100%");
lo.addComponent(help);
lo.setMargin(true);
lo.setSpacing(true);
lo.setWidth("100%");
lo.setSizeFull();
return lo;
}
public void buttonClick(ClickEvent event) {
final Button source = event.getButton();
if (source == search) {
Notification.show("Search hit");
} else if (source == newContact) {
Notification.show("New contact");
} else if (source == help) {
Notification.show("Help");
} else if (source == share) {
Notification.show("Share");
}
}
#Override
public void enter(ViewChangeEvent event) {
// TODO Auto-generated method stub
}
}
You nested two VerticalLayouts for the left menu.
When you wish to fill the whole height, then setting the height to 100% is the correct way to do it.
A VerticalLayout usually distributes the space between the components.
If you don't wish this, then you can set expansionratios to tell it which component should use how much space.
In the constructor change the line calling the createVerticalToolbar to this:
.....
createVerticalToolbar(menuLayout);
.....
private void createVerticalToolbar(VerticalLayout lo) {
newContact.setStyleName("img");
newContact.setWidth("100%");
newContact.setIcon(new ClassResource("../../com/image/document-add.png"));
newContact.addListener((Button.ClickListener) this);
lo.addComponent(newContact);
search.setIcon(new ClassResource("../../com/image/folder-add.png"));
search.addListener((Button.ClickListener) this);
search.setWidth("100%");
lo.addComponent(search);
share.setIcon(new ClassResource("../../com/image/users.png"));
share.addListener((Button.ClickListener) this);
share.setWidth("100%");
lo.addComponent(share);
help.setIcon(new ClassResource("../../com/image/help.png"));
help.addListener((Button.ClickListener) this);
help.setWidth("100%");
lo.addComponent(help);
// Add new component which uses up the remaining space
Label lbl= new Label("About");
lo.addComponent(lbl);
lo.setExpandRatio(help, 20);
lo.setMargin(true);
lo.setSpacing(true);
lo.setWidth("100%");
lo.setSizeFull();
return lo;
}

How to display rows into accordion

I have this JavaFX accordion which displays images:
public class Navigation {
private static final Image BLUE_FISH = new Image("/Blue-Fish-icon.png");
private static final Image RED_FISH = new Image("/Red-Fish-icon.png");
private static final Image YELLOW_FISH = new Image("/Yellow-Fish-icon.png");
private static final Image GREEN_FISH = new Image("/Green-Fish-icon.png");
public void initNavigation(Stage primaryStage, Group root, Scene scene) {
VBox stackedTitledPanes = createStackedTitledPanes();
ScrollPane scroll = makeScrollable(stackedTitledPanes);
scroll.getStyleClass().add("stacked-titled-panes-scroll-pane");
scroll.setPrefSize(395, 580);
scroll.setLayoutX(5);
scroll.setLayoutY(32);
//scene = new Scene(scroll);
root.getChildren().add(scroll);
}
private VBox createStackedTitledPanes() {
final VBox stackedTitledPanes = new VBox();
stackedTitledPanes.getChildren().setAll(
createTitledPane("Connections", GREEN_FISH),
createTitledPane("Tables", YELLOW_FISH),
createTitledPane("Description", RED_FISH),
createTitledPane("Blue Fish", BLUE_FISH));
((TitledPane) stackedTitledPanes.getChildren().get(0)).setExpanded(true);
stackedTitledPanes.getStyleClass().add("stacked-titled-panes");
return stackedTitledPanes;
}
public TitledPane createTitledPane(String title, Image... images) {
FlowPane content = new FlowPane();
for (Image image : images) {
ImageView imageView = new ImageView(image);
content.getChildren().add(imageView);
FlowPane.setMargin(imageView, new Insets(10));
}
content.setAlignment(Pos.TOP_CENTER);
TitledPane pane = new TitledPane(title, content);
pane.getStyleClass().add("stacked-titled-pane");
pane.setExpanded(false);
return pane;
}
private ScrollPane makeScrollable(final VBox node) {
final ScrollPane scroll = new ScrollPane();
scroll.setContent(node);
scroll.viewportBoundsProperty().addListener(new ChangeListener<Bounds>() {
#Override
public void changed(ObservableValue<? extends Bounds> ov, Bounds oldBounds, Bounds bounds) {
node.setPrefWidth(bounds.getWidth());
}
});
return scroll;
}
}
I'm interested is it possible to display rows of data where the images are placed. Something like this:
P.S case example. I have a java object which will be used as list:
public List<dataObj> list = new ArrayList<>();
public class dataObj {
private int connectionId;
private String conenctionname;
private String connectionDescription;
public dataObj() {
}
....................
}
When I insert some data into the Java Array list I want to display it into the accordion based on the above requirement.
P.S 2 In my case what is the proper way to insert text into FlowPane? I tested this:
public TitledPane createTitledPane(String title, Image... images) {
FlowPane content = new FlowPane();
for (Image image : images) {
ImageView imageView = new ImageView(image);
content.getChildren().add(imageView);
FlowPane.setMargin(imageView, new Insets(10));
}
content.setAlignment(Pos.TOP_CENTER);
content.setText("This part will be the first line.\n This part the second.");
TitledPane pane = new TitledPane(title, content);
pane.getStyleClass().add("stacked-titled-pane");
pane.setExpanded(false);
return pane;
}
I get error that inserting text using setText is not correct. What is the proper way?
If you use "\n" the output String will be separated into multiple lines of text.
For example:
component.setText("This part will be the first line.\n This part the second.");
From your update, assuming you have getters and setters:
component.setText(String.valueOf(dataObj.getConnectionId()) + "\n" + dataObj.getConnectionname() + "\n" + dataObj.getConnectionDescription());
You can simply use a ListView:
private void hello() {
ListView<Object> lv = new ListView<>();
// yourList is you List<Object> list
lv.itemsProperty().set(yourList);
lv.setCellFactory(new Callback<ListView<Object>, ListCell<Object>>() {
#Override
public ListCell<Object> call(ListView<Object> p) {
return new youCellFactory();
}
});
AnchorPane content = new AnchorPane();
content.getChildren().add(lv);
// add to TitelPane
TitledPane pane = new TitledPane(title, content);
}
static class youCellFactory extends ListCell<Object> {
#Override
public void updateItem(Object item, boolean empty) {
super.updateItem(item, empty);
if (item != null) {
setText(item.getConenctionname());
}
}
}
I have not tested this code but it should work.
Here is an nice Example too, but without object:
ListViewSample.java

Categories

Resources