I want to make tabs in tab in Vaadin. I'm using tabs with routes https://cookbook.vaadin.com/tabs-with-routes/a . It is working fine when I have only one level of tabs. I dont know how to display Main Tabs, tabs under and its content. How to achieve something like that:
MainView.java
#Route("")
public class MainView extends VerticalLayout implements RouterLayout {
private Map<Tab, String> tabToUrlMap = new LinkedHashMap<>();
public MainView(){
H1 title = new H1("CMS");
Tabs tabs = getTabs();
UI.getCurrent().navigate(OrderGUI.class);
tabs.addSelectedChangeListener(e -> UI.getCurrent().navigate(tabToUrlMap.get(e.getSelectedTab())));
add(title, tabs);
}
private Tabs getTabs() {
RouteConfiguration routeConfiguration = RouteConfiguration.forApplicationScope();
tabToUrlMap.put(new Tab("Zamówienia"), routeConfiguration.getUrl(OrderGUI.class));
//code for rest tabs
Tabs tabs = new Tabs(tabToUrlMap.keySet().toArray(new Tab[]{}));
tabs.getStyle().set("margin", "auto");
return tabs;
}
}
OrderGUI.java
#Route(value="zamowienia", layout = MainView.class)
public class OrderGUI extends VerticalLayout implements RouterLayout{
private Map<Tab, String> tabToUrlMapOrder = new LinkedHashMap<>();
public OrderGUI() {
//super();
Tabs tabs = getTabsOrder();
UI.getCurrent().navigate(OrderedOrderGUI.class);//pierwsza zakładka jako główna
tabs.addSelectedChangeListener(e -> UI.getCurrent().navigate(tabToUrlMapOrder.get(e.getSelectedTab())));
add(tabs);
}
private Tabs getTabsOrder() {
RouteConfiguration routeConfiguration = RouteConfiguration.forApplicationScope();
tabToUrlMapOrder.put(new Tab("Złożone"), routeConfiguration.getUrl(OrderedOrderGUI.class));
tabToUrlMapOrder.put(new Tab("W produkcji"), routeConfiguration.getUrl(ProductionOrderGUI.class));
tabToUrlMapOrder.put(new Tab("Gotowe"), routeConfiguration.getUrl(ReadyOrderGUI.class));
Tabs tabs = new Tabs(tabToUrlMapOrder.keySet().toArray(new Tab[]{}));
tabs.getStyle().set("margin", "auto");
return tabs;
}
}
OrderedOrderGUI.java
#Route(value="zamowienia/zlozone", layout = OrderGUI.class)
public class OrderedOrderGUI extends VerticalLayout {
public OrderedOrderGUI() {
add(new Text("some content"));
}
}
Problem solved, I had to add annotation #ParentLayout(MainView.class) in OrderGUI.java
Related
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");
}
}
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.
i cannot get a navigator to run within my project.
i always get the Error
"Component must be attached to a session when getConnectorId() is called for the first time"
i followed several examples where it ran out of the box with nealy the exact same setup but i cannot get it to run within my environment and i don't know why.
This is my MainUI
#SpringUI
public class MainUI extends UI implements View{
HorizontalLayout root;
#Override
protected void init(VaadinRequest request) {
root = new HorizontalLayout();
VerticalLayout menu = this.createMenuBar();
menu.setWidth("20%");
root.addComponents(menu);
Panel viewPanel = new Panel();
root.addComponentsAndExpand(viewPanel);
setContent(root);
final Navigator navigator = new Navigator(this, viewPanel);
navigator.addView("Food", FoodView.class);
navigator.addView("Meal", MealView.class);
navigator.addView("", MainView.class);
// even with
//navigator.addView("Main", MainView.class);
//navigator.navigateTo("Main");
// i get the same error
}
#Override
public void enter(ViewChangeEvent event) {
// TODO
}
private VerticalLayout createMenuBar() {
VerticalLayout menuBar = new VerticalLayout();
for(String s: new String[] {"Food", "Meal"}) {
menuBar.addComponents(this.createNavigationButton(s, this.getNavigator()));
}
return menuBar;
}
private Button createNavigationButton(final String state, final Navigator navigator) {
return new Button("Go go" + state, new Button.ClickListener() {
#Override
public void buttonClick(ClickEvent event) {
navigator.navigateTo(state);
}
});
}
}
This is my Main/Food/Meal View, they are only stumps with only a label because i just wanted to test a Multipage example
#SpringView(name = MainView.VIEW_NAME)
public class MainView extends UI implements View {
public static final String VIEW_NAME = "Main";
#Override
protected void init(VaadinRequest request) {
VerticalLayout root = new VerticalLayout();
setContent(root);
Label lbl = new Label("MainView");
root.addComponent(lbl);
}
#Override
public void enter(ViewChangeEvent event) {
}
}
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;
}
I have two JPanels nested inside a cardPanl(with a cardLayout).
When switching between pages I need to have new instance of the page created. For example when I switch from homePage to captchaPage, I will replace the current homePage with a new instance of 'HomePage'. same thing goes when switching from captchaPage to homePage.
I will create the new instances without any problem but what I see on the screen is the old view of the JPanels meaning they do not get repainted.
I've searched for this problem and almost all the solutions suggest calling revalidate(), validate() or repaint() on the panel.
I've did it all and still I get the old view. I'm sure that creating the new instances is done successfully because when printing the capthcha in the console i see that it changes but the view remains the same.
Here is my structure:
BasicPage.java
public class BasePage extends JPanel {
protected JFrame parent;
protected String name;
public BasePage(JFrame parent, String name) {
this.parent = parent;
this.name = name;
// ...
}
}
CaptchaPage.java
public class CaptchaPage extends BasePage {
private String challenge;
public CaptchaPage(JFrame parent, String name) {
super(parent, name);
challenge = new BigInteger(130, new SecureRandom()).toString(32);
challenge = challenge.length() > 5 ? challenge.substring(0, 5) : challenge;
JLabel label = new JLabel(challenge);
this.add(label);
}
}
Dashboard.java
public class Dashboard extends JFrame {
private JPanel cardPanel;
private BasePage homePage;
private BasePage captchaPage;
public Dashboard() {
cardPanel = new JPanel();
cardPanel.setLayout(new CardLayout());
homePage = new HomePage(this, "0");
captchaPage = new CaptchaPage(this, "1");
cardPanel.add(homePage, "0");
cardPanel.add(captchaPage, "1");
this.add(cardPanel);
}
protected void switchPage(String name) {
((CardLayout)cardPanel.getLayout()).show(cardPanel, name);
if (name.equals("1")) {
homePage = new HomePage(this, "0");
homePage.revalidate();
}
else {
captchaPage = new CaptchaPage(this, "1");
captchaPage.revalidate();
}
}
}
Answer
BasePage page = new HomePage(this, "0");
cardPanel.add(page, "0");
cardPanel.revalidate();
homePage = page;
You added panels to the CardLayout with the following code which is correct:
cardPanel.add(homePage, "0");
cardPanel.add(captchaPage, "1");
Now you are trying to update the CardLayout with code like:
homePage = new HomePage(this, "0");
That will not work. All you are doing is changing the reference of the homepage variable. You have not added the component to the CardLayout.
To change the panel then code should be the same as the code you used to add the panel initially:
JPanel homepage = new HomePage(...);
cardPanel.add(...);
Why are you changing the components on the panel? Why does the homepage change. Sounds like a strange design to me.