user12106967
user12106967

Reputation:

Horizontal button bar with slider in Vaadin

My goal is to create a horizontal button bar with a variable number of buttons in it. Each button click should open a certain, new gui that is embedded into the extisting one, above the HorizontalLayout. Image

The first button should always be there. This is the code so far:

public class MainLayout extends VerticalLayout implements PageConfigurator
{
    int number = 10;

/**
 *
 */
public MainLayout()
{
    super();
    this.initUI();
    this.createButtons();
}

private void createButtons()
{
    for(int i = 1; i <= this.number; i++)
    {
        final Button button = new Button();
        button.setText("Button" + i);
        button.setHeight("120px");
        button.setWidth("120px");

        this.horizontalLayout.addComponentAtIndex(i, button);
    }
}

@Override
public void configurePage(final InitialPageSettings settings)
{
    settings.addLink("shortcut icon", "frontend/images/favicon.ico");
    settings.addFavIcon("icon", "frontend/images/favicon256.png", "256x256");
}

/* WARNING: Do NOT edit!<br>The content of this method is always regenerated by the UI designer. */
// <generated-code name="initUI">
private void initUI()
{
    this.div              = new Div();
    this.horizontalLayout = new HorizontalLayout();
    this.button           = new Button();

    this.button.setText("Button");

    this.button.setWidth("120px");
    this.button.setHeight("120px");
    this.horizontalLayout.add(this.button);
    this.div.setWidth("100px");
    this.div.setHeight("100px");
    this.horizontalLayout.setWidthFull();
    this.horizontalLayout.setHeight("100px");
    this.add(this.div, this.horizontalLayout);
    this.setSizeFull();
} // </generated-code>

// <generated-code name="variables">
private Button           button;
private HorizontalLayout horizontalLayout;
private Div              div;
// </generated-code>

}

My questions:

Upvotes: 2

Views: 594

Answers (2)

Basil Bourque
Basil Bourque

Reputation: 339689

Tabs

You are replicating the functionality already built into the Vaadin Tabs and Tab widgets. No need to re-invent the wheel here. Furthermore, you will confuse your user by having buttons that act like tabs, merely switching between content panels within the window.

Screenshot of "Tabs" widget in use with a scroll control or the right edge, along with its source code

Tabs have the features you asked for:

  • Switching content panels within window
  • Scrolling if too many to fit on the screen
  • Appearance can be customized via Vaadin themes (Lumo & Material) and CSS.
    (See examples at bottom of this page.)
  • Tabs can be added and removed. You can also disable a tab, to be faded yet still readable while inactive.

To switch content, merely hide or show by calling setVisible. Hiding via CSS is very fast. And setVisible to false also shuts off updates to the Vaadin component from the Vaadin server, so you can freshen the hidden content (if need be) without the cost of updating the browser unnecessarily.

The Tabs with pages section of that examples page gives you a nice code example for managing content switching. A Map tracks the relationship of each tab to its content. The listener method at the bottom switches content by hiding & showing. Copied here:

Tab tab1 = new Tab("Tab one");
Div page1 = new Div();
page1.setText("Page#1");

Tab tab2 = new Tab("Tab two");
Div page2 = new Div();
page2.setText("Page#2");
page2.setVisible(false);

Tab tab3 = new Tab("Tab three");
Div page3 = new Div();
page3.setText("Page#3");
page3.setVisible(false);

Map<Tab, Component> tabsToPages = new HashMap<>();
tabsToPages.put(tab1, page1);
tabsToPages.put(tab2, page2);
tabsToPages.put(tab3, page3);
Tabs tabs = new Tabs(tab1, tab2, tab3);
Div pages = new Div(page1, page2, page3);
Set<Component> pagesShown = Stream.of(page1)
        .collect(Collectors.toSet());

tabs.addSelectedChangeListener(event -> {
    pagesShown.forEach(page -> page.setVisible(false));
    pagesShown.clear();
    Component selectedPage = tabsToPages.get(tabs.getSelectedTab());
    selectedPage.setVisible(true);
    pagesShown.add(selectedPage);
});

PagedTabs widget

As you can see from that code snippet above, the Tabs & Tab widgets bundled with Vaadin do not actually switch content. Those widgets are just the bare minimum for (a) displaying themselves on screen in a theme-compliant manner, and (b) knowing when they have been clicked.

Fortunately, Alejandro Duarte authored a widget wrapping Tabs & Tab. The paged-tabs is described on the Vaadin Directory. You can download, or install via Maven. The product is free-of-cost and open-source (Apache License 2).

With PagedTabs, you pass content while adding each tab. That content is automatically swapped when clicking between tabs. No need for you to track which content belongs to which tab. And no need for you to show/hide content. The widget includes methods for adding or removing tabs, removing the matching content as well. Indeed, this widget supports having a "Close" control to delete a tab.

Screenshot of "paged-tabs" widget in use on a web page

Unfortunately, I cannot get this PagedTabs widget to constrain itself to the width of the browser window. The scroll control never appears within the tab bar. Instead, the user must scroll the entire web page to the right to access the extra tabs. I filed Issue # 11.

This PagedTabs project is certainly a good idea and looks promising. Check it out, perhaps that problem will be fixed, or perhaps you can find a workaround.

Upvotes: 1

kscherrer
kscherrer

Reputation: 5766

How do i get a slider in my horizontal layout for the buttons?

For this I recommend using the add-on ScrollLayout which provides the two classes VerticalScrollLayout and HorizontalScrollLayout. You would use the horizontal one for this case. Use it like any other HorizontalLayout, but if there's not enough space to display all content, it will expand horizontally and add a horizontal scrollbar. I made this add-on myself so if there's any problem don't hesitate to ask. (There is no V14 version of this add-on but you can use the V13 version in your V14 project, it's compatible)

Later on i would like to update the button bar, so "number" will change at runtime. The button bar should recognize this change and create as many buttons as given. How do i implement the updating?

1) Remove all existing buttons
2) Add the right amount of buttons again

private void updateButtons(){
    this.horizontalLayout.removeAll();
    createButtons();
}

Edit: This is the easy way of doing it, by removing ALL buttons then re-adding the right amount. If you want to be a little more fancy, you could try to keep some buttons if they're gonna be readded anyway. example: let's say you initially have 4 Buttons. When you change the number to 3, you would only have to remove the last Button, instead of removing 4 then adding 3. This would have the upside that any changes you may have done in the respective shown layouts of the buttons would not be discarded. This would be an important difference if you're using a Binder inside the shown/hidden layouts.


As a sidenote, you are basically implementing the functionality of Tabs with buttons here. While this is certainly possible, I would recommend you try it with Tabs. I know you tried it yesterday but I think you gave up too soon. I realize the Tabs are somewhat complicated, but you will have to create similar complexity using this button solution (the current implementation of yours is not finished yet - you still have to create a layout that shows for each button, and add a click listener that will trigger this visibility change)

Upvotes: 2

Related Questions