I'm developing a web application in Vaadin framework which has home page and few sub pages. What I want to achieve is to have fixed header and footer and in the center have content, that is being changed and fill all the space between header and footer. This is my MainUI class:
// HEADER
final VerticalLayout headerLayout = new VerticalLayout();
final Panel headerPanel = new Panel();
headerPanel.addStyleName("header");
final ActiveLink header = new ActiveLink(provider.getText(getLocale(), "application.title.name"), new ExternalResource(""));
header.addStyleName("header");
header.addListener((ActiveLink.LinkActivatedListener) (ActiveLink.LinkActivatedEvent event) -> {
getUI().getNavigator().navigateTo(Constant.View.MAIN);
});
headerPanel.setContent(header);
headerLayout.addComponent(headerPanel);
// FOOTER
final VerticalLayout footerLayout = new VerticalLayout(new Label("« FOOTER »"));
// CONTENT
final VerticalLayout contentLayout = new VerticalLayout();
final Panel contentPanel = new Panel(contentLayout);
contentPanel.addStyleName("content transparent no-border");
// MAIN = all together
final VerticalLayout mainLayout = new VerticalLayout(headerLayout, contentPanel, footerLayout);
mainLayout.setSizeFull();
mainLayout.setExpandRatio(contentPanel, 1);
setContent(mainLayout);
// Register Views in navigator
navigator = new Navigator(this, contentPanel);
navigator.addView("", new MainView(provider));
navigator.addView(Constant.View.DICT_ADMIN, new DictAdminView(provider));
For changing the view in content I'm using Navigator like this in MainView class:
final ActiveLink link11 = new ActiveLink(provider.getText(getLocale(), "menu.links.dict.admin"), new ExternalResource(""));
link11.addStyleName("menulinks");
link11.addListener((LinkActivatedListener) (LinkActivatedEvent event1) -> {
getUI().getNavigator().navigateTo(Constant.View.DICT_ADMIN);
});
And finally this is my DictAdminView class:
public class DictAdminView extends GridLayout implements View {
private static final Logger LOGGER = LoggerFactory.getLogger(DictAdminView.class);
I18NProvider provider;
private final DictionaryDao dictionaryDao = new DictionaryDao();
private final TermDao termDao = new TermDao();
private final JPAContainer dictionaries = dictionaryDao.getContainer();
private final JPAContainer terms = termDao.getContainer();
public DictAdminView(I18NProvider provider) {
super(4, 6);
this.provider = provider;
}
#Override
public void enter(ViewChangeListener.ViewChangeEvent event) {
removeAllComponents();
this.addStyleName("dictAdminLayout");
this.setSizeFull();
this.setSpacing(true);
// Table with Dictionaries
Grid grid = new Grid(dictionaries);
grid.setId("dictList");
grid.setWidth("100%");
grid.setColumns(
grid.getColumns().get(1).getPropertyId(),
grid.getColumns().get(0).getPropertyId());
grid.getColumns().get(1).setWidth(80).setHeaderCaption("POS");
this.addComponent(grid, 0, 0, 0, 5);
dictionaries.sort(new Object[]{grid.getColumns().get(0).getPropertyId()}, new boolean[]{true});
// Table with Terms
Grid grid1 = new Grid(terms);
grid1.setId("termList");
grid1.setWidth("100%");
grid1.setColumns(
grid1.getColumns().get(5).getPropertyId(),
grid1.getColumns().get(0).getPropertyId());
this.addComponent(grid1, 1, 0, 3, 3);
terms.sort(new Object[]{grid1.getColumns().get(0).getPropertyId()}, new boolean[]{true});
terms.addContainerFilter(new IsNull("dictionaryId")); // show items w/o dict by default
this.addComponent(new Button("lol button"), 1, 5, 3, 5);
// Handle dictionary selection
grid.addSelectionListener(selectionEvent -> {
// Get selection from the selection model
Integer selectedDictionaryId = (Integer) ((SingleSelectionModel) grid.getSelectionModel()).getSelectedRow();
terms.removeAllContainerFilters();
if (selectedDictionaryId != null) {
terms.addContainerFilter(new Compare.Equal("dictionaryId.id", selectedDictionaryId));
Utils.showInfoMessage(provider.getText(getLocale(), "msg.info.title.dictionary.selected"),
grid.getContainerDataSource().getItem(selectedDictionaryId).getItemProperty("name").toString());
}
else {
terms.addContainerFilter(new IsNull("dictionaryId")); // show items w/o dict by default
Utils.showInfoMessage(provider.getText(getLocale(), "msg.info.title.nothing.selected"), "");
}
});
}
}
My problem here is that I can't stretch the Grid to fill all space between header and footer. I've tried combination of setSizeFull() and setRowExtendRatio() but no success. Also I've tried to do it in CSS.
Is there a way how to stretch the grid either in Java or CSS?
Is the Navigator and changing View a good approach or is there a better way how to switch between content?
The solution is to use Vaadin add-on BorderLayout or built-in CustomLayout with own HTML and CSS.
Related
I am still new in Vaadin and I am trying to implement #polymenr/paper-slider component using Vaadin 14.
I have downloaded the project https://github.com/berndhopp/vaadin-paper-sliders from Github and I am trying to set "pin" property as explained here
https://vaadin.com/forum/thread/18215247/vaadin-14-slider
In PaperSlider.java
...
public void setPin(boolean pin) {
this.getElement().setProperty("pin", pin);
}
...
In DemoView.java
package org.vaadin.addon.sliders.ui;
//import org.vaadin.addon.sliders.PaperSlider;
import org.vaadin.addon.sliders.PaperSlider;
import com.vaadin.flow.component.html.Anchor;
import com.vaadin.flow.component.html.H3;
import com.vaadin.flow.component.html.Label;
import com.vaadin.flow.component.orderedlayout.HorizontalLayout;
import com.vaadin.flow.component.orderedlayout.VerticalLayout;
import com.vaadin.flow.router.Route;
#Route("")
public class DemoView extends VerticalLayout
{
private PaperSlider slider = null;
private Label sliderValue = null;
public DemoView()
{
Anchor sourceLink = new Anchor("https://github.com/markhm/vaadin-paper-sliders", " (source code on GitHub)");
sourceLink.setTarget("_blank");
HorizontalLayout titleBox = new HorizontalLayout();
titleBox.setAlignItems(Alignment.BASELINE);
H3 title = new H3("Vaadin paper-slider, ported to Vaadin v14");
titleBox.add(title, sourceLink);
add(titleBox);
//
// https://stackoverflow.com/questions/68531460/vaadin-14-paper-slider-pin-property
//
HorizontalLayout sliderLine = new HorizontalLayout();
sliderLine.setHeight("100px");
Label sliderValue = new Label();
PaperSlider paperSlider = new PaperSlider(0,100,20);
paperSlider.addValueChangeListener(e -> sliderValue.setText("New Slider value: " + e.getValue()));
paperSlider.setPin(true);
sliderLine.add(paperSlider, sliderValue);
add(sliderLine);
// slider.getElement().getStyle().set("padding-top", "30px") ;
//Label whiteline = new Label("");
//whiteline.setHeight("50px");
//add(whiteline);
// Testing pin property
// HorizontalLayout mySliderLine = new HorizontalLayout();
//sliderValue = new Label("mySlider value");
//PaperSlider paperSlider = new PaperSlider(0,100,20);
//paperSlider.getElement().getStyle().set("padding-top", "30px");
//mySliderLine.setHeight("100px");
//paperSlider.setPin(true);
//mySliderLine.add(paperSlider);
// slider.setPin(true) ;
// add(slider) ;
// NB: The PaperRangeSlider does not support Polymer 3.
// HorizontalLayout rangeSliderLine = new HorizontalLayout();
//
// Label rangeValues = new Label("Range values");
// rangeSlider = new PaperRangeSlider(0, 100, 40, 60);
// rangeSlider.addValueChangeListener(e -> rangeValues.setText("Range values: " + e.getValue()));
// rangeSliderLine.add(rangeSlider, rangeValues);
// add(rangeSliderLine);
}
}
I can see the paper slider but I don't see the numeric value label when the slider thumb is pressed.
Can anyone help with this please
Thanks
Alex
It seems numeric value get lost within the layout. You can try adding height to the layout, something like sliderLine.setHeight("100px") or adding some padding to the component paperSlider.getElement().getStyle().set("padding-top", "30px").
from the original post I missed the part that you have an extra Label component and that's the value that you can't see. If I do this:
HorizontalLayout sliderLine = new HorizontalLayout();
sliderLine.setHeight("100px");
Label sliderValue = new Label();
PaperSlider paperSlider = new PaperSlider(0,100,20);
paperSlider.addValueChangeListener(e -> sliderValue.setText("New Slider value: " + e.getValue()));
paperSlider.setPin(true);
sliderLine.add(paperSlider, sliderValue);
add(sliderLine);
I get to see that label with the selected value
After implementing nested layouts i faced the problem with rendering component containing grid. The analysis shows that is present in html but it has display-block attributes and the grid is never visible.
I read the similar question (Vaadin 14 - Grid not Displaying/Populating When Used in Nested Layout) but the suggestions listed there brought me no result.
Here comes my code:
MainLayout.kt:
#Theme(value = Material::class, variant = Material.DARK)
class MainLayout : Composite<Div>(), RouterLayout {
//Component to delegate content through.
private val mainContent: Div = Div()
private val layout = VerticalLayout(
Span("from MainLayout top"),
mainContent,
Span("from MainLayout bottom"))
override fun showRouterLayoutContent(hasElement: HasElement) {
Objects.requireNonNull(hasElement)
Objects.requireNonNull(hasElement.element)
mainContent.removeAll()
mainContent.element.appendChild(hasElement.element)
}
init {
content.add(layout)
}
}
LayoutWithMenuBar.kt:
#ParentLayout(value = MainLayout::class)
class LayoutWithMenuBar : Composite<Div>(), RouterLayout {
private val mainContent: Div = Div()
private val menuBar = HorizontalLayout(
RouterLink("Home", MainView::class.java),
RouterLink("Tprojects", TProjectDashboard::class.java),
RouterLink("ViewA", ViewA::class.java),
RouterLink("ViewB", ViewB::class.java))
private val root = VerticalLayout(menuBar, mainContent)
override fun showRouterLayoutContent(hasElement: HasElement) {
Objects.requireNonNull(hasElement)
Objects.requireNonNull(hasElement.element)
mainContent.removeAll()
mainContent.element.appendChild(hasElement.element)
}
init {
content.add(root)
}
}
and a component containing grid - TProjectDashboard:
#Route("dashboard/tproject", layout = LayoutWithMenuBar::class)
class TProjectDashboard(#Autowired val tprojectService: TProjectService): VerticalLayout() {
var tprojectGrid = Grid<TProject>(TProject::class.java)
init {
//tprojectGrid
tprojectGrid.setColumns(
TProject::tprojectUuid.name,
TProject::tprojectClass.name,
TProject::tprojectState.name,
TProject::tentityState.name,
TProject::size.name)
tprojectGrid.setItems(tprojectService.findAll())
tprojectGrid.setSizeFull()
tprojectGrid.setWidthFull()
tprojectGrid.setHeightFull()
add(tprojectGrid)
setSizeFull()
setHeightFull()
setWidthFull()
}
}
The same result i have when changing TProjectDashboard parent from VerticalLayout to Composite.
The nested layouts approach works well for simple components like Span and if i remove layout reference from #Route annotation i will see my grid.
Here is the screen how it looks like now:
enter image description here
Would appreciate for any hints or solutions.
Thanks in advance.
It's probably a sizing issue that unfortunately happens too often. I would start with calling setSizeFull() on the mainContent div. If that doesn't help, go through the elements in the browser devtools and try to see where the size disappears, e.g. what is the first element that has 0 width or height.
Edit: Setting setSizeFull() on all components works. I would simplify your layouts slightly, though, by changing the composites to be of type VerticalLayout. Then you can get rid of a lot of the setSizeFull() calls.
The code below is in Java as I don't have Kotlin set up, you can call getContent().setSizeFull() in MainLayout if you want it to take the full height of the page.
MainLayout
#Theme(value = Material.class, variant = Material.DARK)
public class MainLayout extends Composite<VerticalLayout> implements RouterLayout {
//Component to delegate content through.
private Div mainContent = new Div();
public MainLayout() {
getContent().add(
new Span("from MainLayout top"),
mainContent,
new Span("from MainLayout bottom"));
mainContent.setSizeFull();
}
#Override
public void showRouterLayoutContent(HasElement hasElement) {
Objects.requireNonNull(hasElement);
Objects.requireNonNull(hasElement.getElement());
mainContent.removeAll();
mainContent.getElement().appendChild(hasElement.getElement());
}
}
LayoutWithMenuBar
#ParentLayout(value = MainLayout.class)
public class LayoutWithMenuBar extends Composite<VerticalLayout> implements RouterLayout {
private Div mainContent = new Div();
private HorizontalLayout menuBar = new HorizontalLayout(
new RouterLink("Tprojects", TProjectDashboard.class));
public LayoutWithMenuBar() {
getContent().add(menuBar, mainContent);
mainContent.setSizeFull();
}
#Override
public void showRouterLayoutContent(HasElement hasElement) {
Objects.requireNonNull(hasElement);
Objects.requireNonNull(hasElement.getElement());
mainContent.removeAll();
mainContent.getElement().appendChild(hasElement.getElement());
}
}
TProjectDashboard
#Route(value = "dashboard/tproject", layout = LayoutWithMenuBar.class)
public class TProjectDashboard extends VerticalLayout {
private Grid<TProject> tprojectGrid = new Grid<>(TProject.class);
public TProjectDashboard() {
tprojectGrid.setItems(
new TProject("Erik", "Software Engineer"),
new TProject("Fia", "Kindergarden teacher"),
new TProject("Jack", "All trades")
);
add(tprojectGrid);
}
}
I need to put a grid in dialog but the grid is very small.
Grid<FermetureGagnanteTexte> fermetureGagnanteTexteGrid = new Grid<>(FermetureGagnanteTexte.class,false);
verticalLayout.add(fermetureGagnanteTexteGrid);
dialog.add(verticalLayout);`
dialog.open();
The grid is very small in the dialog.
Here is a solution for Vaadin 8 by using the Window Component.
By the description of your problem i assume that you did not set any size attributes with setWidth, setHeight or setSizefull. Even my code example is specific for Vaadin 8 it should also apply to the Dialog-component for Vaadin-Flow.
import com.vaadin.server.VaadinRequest;
import com.vaadin.spring.annotation.SpringUI;
import com.vaadin.ui.Grid;
import com.vaadin.ui.UI;
import com.vaadin.ui.Window;
#SpringUI
public class TestUI extends UI {
#Override
protected void init(final VaadinRequest request) {
showGridInWindow();
}
private void showGridInWindow() {
final Window window = new Window("Window Caption");
final Grid<Object> grid = new Grid<>();
grid.addColumn(Object::toString).setCaption("Column 1");
grid.setSizeFull();
final List<Object> items = new ArrayList<>();
for (int i = 0; i < 50; i++) {
items.add(new String("String #" + i));
}
grid.setItems(items);
window.setContent(grid);
window.setWidth("600px");
window.setHeight("400px");
window.setModal(true);
window.setClosable(true);
getUI().addWindow(window);
}
}
If you are using Vaadin Flow, put the grid into a Div() instead of a VerticalLayout. Add the Div to the Dialog and set the Dialog's size. The Grid should fill the space and scroll.
Grid<FermetureGagnanteTexte> grid = new Grid<>(FermetureGagnanteTexte.class);
Dialog dialog = new Dialog();
Div div = new Div();
div.add(grid);
dialog.add(div);
dialog.setWidth("600px");
dialog.open();
S.
I need to make a GUI interface (using BorderLayout) that looks like the image attached.(http://i.imgur.com/wRN4vlH.jpg)
the issue is that I am not allowed to restrict resizing and the buttons can not move to another row. I have the code working to display the proper image I dont know how to make it show the buttons without resizing and without the buttons moving. Any suggestions would be truly helpful
import java.awt.*;
import javax.swing.*;
class MyComponents extends JFrame{
MyComponents (String title){
JFrame frame = new JFrame(title);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
BorderLayout layout = new BorderLayout(2,3);
frame.setLayout(layout);
JPanel northPanel = new JPanel();
//JPanel westPanel = new JPanel();
JPanel centerPanel = new JPanel();
//JPanel eastPanel = new JPanel();
JTextField Text = new JTextField();
northPanel.add(new JLabel("Current Value:"));
northPanel.add(Text);
Text.setPreferredSize(new Dimension(50,24));
centerPanel.add(new JButton("+"));
centerPanel.add(new JButton("-"));
centerPanel.add(new JButton("Reset"));
centerPanel.add(new JButton("Quit"));
frame.add(northPanel, BorderLayout.NORTH);
frame.add(centerPanel, BorderLayout.CENTER);
frame.setVisible(true);
}
}
public class Homework7b {
public static void main (String [] args)
{
MyComponents Homework7b = new MyComponents("Part 02 Using getSource");
}
}
I am using PaneManagerDemo project code (this project is present in sample demo projects of BB) for developing tab.
I am facing one problem when I select tab it got focus but when I select data below that tab the focus goes to that data.
I want when user select data under tab, it must focus on that data as well as the tab so that user can understand selected data is under which tab.
I am not getting it.
Please tell me.
Here is code for the reference.
public class PaneManagerDemo extends UiApplication
{
public static void main(String[] args)
{
UiApplication app = new PaneManagerDemo();
app.enterEventDispatcher();
}
public PaneManagerDemo()
{
invokeLater(new Runnable()
{
public void run()
{
int headerType = 0;
// Display a dialog for user to select header type
OptionDialog dialog = new OptionDialog();
int result = dialog.doModal();
if(result == Dialog.OK)
{
headerType = dialog.getHeaderType();
}
else if(result == Dialog.CANCEL)
{
System.exit(0);
}
//PaneScreen screen = new PaneScreen(headerType);
PaneScreen screen = new PaneScreen(headerType);
pushScreen(screen);
}
});
}
/**
* A dialog popup used to choose a header type
*/
private static class OptionDialog extends Dialog
{
public static final int SCROLL_HEADER_TYPE = 0;
public static final int TAB_HEADER_TYPE = 1;
private ObjectChoiceField _choiceField;
/**
* Create a new HeaderDialog object
*/
public OptionDialog()
{
super(Dialog.D_OK_CANCEL, "Choose Header Type", Dialog.OK, null, Dialog.GLOBAL_STATUS);
_choiceField = new ObjectChoiceField("", new String[]{"Scrollable", "Tab"}, 0);
add(_choiceField);
_choiceField.setFocus();
}
/**
* Returns an integer representing the header type
*
* #return SCROLL_HEADER_TYPE if scrollable header selected, TAB_HEADER_TYPE if tab header selected
*/
public int getHeaderType()
{
return _choiceField.getSelectedIndex();
}
}
/**
* Main screen for the application. Displays three panes
* switchable via horizontal scroll field or tabs, depending
* on user selection.
*/
private final static class PaneScreen extends MainScreen
{
/**
* Creates a new PaneScreen object
* #param headerType The header type for the PaneManager, scrollable or tab style
*/
public PaneScreen(int headerType)
{
super(Field.FOCUSABLE);
// Instantiate the model for the pane manager and enable looping
PaneManagerModel model = new PaneManagerModel();
model.enableLooping(true);
// Create a pane
VerticalFieldManager vfm = new VerticalFieldManager();
vfm.add(new LabelField("Data 1"));
XYEdges edgesOne = new XYEdges(1, 1, 1, 1);
vfm.setBorder(BorderFactory.createRoundedBorder(edgesOne));
Pane pane = new Pane(new LabelField("Pane 1", Field.FOCUSABLE | Field.FIELD_HCENTER), vfm);
// Add the pane to the model
model.addPane(pane);
// Create a second pane
vfm = new VerticalFieldManager();
for(int i = 0; i < 30; i++)
{
vfm.add(new LabelField("Data " + i, Field.FOCUSABLE));
}
LabelField iconTextLabelField = new LabelField("Pane 2");
model.addPane(new Pane(iconTextLabelField, vfm));
// Create a third pane
vfm = new VerticalFieldManager();
ButtonField button = new ButtonField("Button", ButtonField.CONSUME_CLICK | ButtonField.NEVER_DIRTY);
button.setChangeListener( new FieldChangeListener()
{
public void fieldChanged(Field field, int context)
{
Dialog.inform("Button activated.");
}
});
vfm.add(button);
model.addPane(new Pane(new LabelField("Pane 3"), vfm));
// Choose which pane the model is displaying
model.setCurrentlySelectedIndex(1);
// Create the header and initialize the model and visual properties
TitleView header = null;
PaneManagerController controller = null;
if(headerType == OptionDialog.SCROLL_HEADER_TYPE)
{
header = new HorizontalScrollableTitleView(Field.FOCUSABLE);
controller = new HorizontalScrollableController();
}
else if(headerType == OptionDialog.TAB_HEADER_TYPE)
{
header = new HorizontalTabTitleView(Field.FOCUSABLE);
((HorizontalTabTitleView)header).setNumberOfDisplayedTabs(model.numberOfPanes());
controller = new HorizontalTabController();
}
else
{
throw new IllegalStateException("Header type is not valid.");
}
header.setModel(model);
XYEdges edgesFour = new XYEdges(4, 4, 4, 4);
header.setBorder(BorderFactory.createRoundedBorder(edgesFour));
// Set arrow images
Bitmap leftArrow = Bitmap.getBitmapResource("leftArrow.png");
Bitmap rightArrow = Bitmap.getBitmapResource("rightArrow.png");
if(leftArrow != null)
{
header.setLeftArrow(leftArrow);
}
if(rightArrow != null)
{
header.setRightArrow(rightArrow);
}
// Create the PaneView object, which will display the panes and is
// controlled by the model.
PaneView paneView = new PaneView(Field.FOCUSABLE);
paneView.setBorder(BorderFactory.createSimpleBorder(edgesOne));
paneView.setModel(model);
// Initialize the PaneManagerView
PaneManagerView view = new PaneManagerView(Field.FOCUSABLE, header, paneView);
view.setModel(model);
view.setBorder(BorderFactory.createRoundedBorder(edgesFour));
model.setView(view);
// Initialize the Controller
controller.setModel(model);
controller.setView(view);
model.setController(controller);
view.setController(controller);
add(view);
}
}
}
Only one field in a screen can hold focus at any one time, so you will need to indicate which tab contains the focused field by other means. e.g. by painting the selected tab a different colour.