How to reverse vaadin Grid?

ぃ、小莉子 提交于 2019-12-13 07:57:16

问题


I'm trying to build a simple java application using Spring Boot and Vaadin. I need to add a table on UI like this: https://www.screencast.com/t/1c4xkr4IE

It could be extended by periods.

Looks like Vaadin Grid element perfectly fits my requirements, but it adds my rows as columns. Is it possible to reverse grid or maybe there is another way to build needed table?

UPDATE

Here are my code:

@SpringComponent
@UIScope
public class MyDataEditor extends VerticalLayout {
private final MyDataRepository repository;
private MyData myData;

TextField month = new TextField("Period");
TextField numberOfWorkers = new TextField(" Number of workers");
TextField numberOfNewcomers = new TextField("Number of newcomers");
TextField numberOfDismissals = new TextField("Number of dismissals");

Button save = new Button("Save");
Button cancel = new Button("Cancel");
Button delete = new Button("Delete");
CssLayout actions = new CssLayout(save, cancel, delete);

Binder<MyData> binder = new Binder<>(MyData.class);

@Autowired
public MyDataEditor(MyDataRepository repository) {
    this.repository = repository;
    addComponents(month, numberOfWorkers, numberOfNewcomers, numberOfDismissals, actions);
    binder.bindInstanceFields(this); 
    setSpacing(true);
    actions.setStyleName(ValoTheme.LAYOUT_COMPONENT_GROUP);
    save.setStyleName(ValoTheme.BUTTON_PRIMARY);
    save.setClickShortcut(ShortcutAction.KeyCode.ENTER);

    save.addClickListener(e -> repository.save(myData));
    delete.addClickListener(e -> repository.delete(myData));
    cancel.addClickListener(e -> editInputData(myData));
    setVisible(false);
}

public interface ChangeHandler {
    void onChange();
}

public final void editMyData(MyData c) {
    if (c == null) {
        setVisible(false);
        return;
    }
    final boolean persisted = c.getMonth() != null;
    if (persisted) {
        myData = repository.findOne(c.getMonth());
    } else {
        myData = c;
    }
    cancel.setVisible(persisted);
    binder.setBean(myData);
    save.focus();
    periodId.selectAll();
}

public void setChangeHandler(ChangeHandler h) {
    save.addClickListener(e -> h.onChange());
    delete.addClickListener(e -> h.onChange());
}

}


@SpringUI
@Theme("valo")
public class VaadinUI extends UI {
private final MyDataRepository repo;
private final MyDataEditor editor;
final Grid<MyData> grid;
private final Button addNewBtn;

@Autowired
public VaadinUI(MyDataRepository repo, MyDataEditor editor) {
    this.repo = repo;
    this.editor = editor;
    this.grid = new Grid<>(MyData.class);
    this.addNewBtn = new Button("Add new month");
}

@Override
protected void init(VaadinRequest request) {

    grid.setHeight(300, Unit.PIXELS);
    grid.setColumns("month", "numberOfWorkers", "numberOfNewcomers", "numberOfDismissals");
    grid.asSingleSelect().addValueChangeListener(e -> {
        editor.editMyData(e.getValue());
    });
    addNewBtn.addClickListener(e -> editor.editMyData(new MyData()));
    editor.setChangeHandler(() -> {
        editor.setVisible(false);
        grid.setItems(repo.findAll());
    });
}
}

So what I mean by this question is that I set

grid.setColumns("month", "numberOfWorkers", "numberOfNewcomers", "numberOfDismissals");

and do not find out method like setRows, so my table looks like: https://www.screencast.com/t/ndDY6tXp, but should be like on first picture.


回答1:


I do believe there is no way to solve it elegantly without CSS or extending the client grid component.

What you could do though is add your data using

List<MyData> data = repo.findAll();
for(int i = 0; i < data.size(); i++)
    grid.addColumn(i)

//String[] months = data.map(x -> x.month).collect(Collectors.toArray)
//String[] nrWork = data.map(x -> x.nrWork).collect(Collectors.toArray)
grid.addRow(months)
grid.addRow(nrWork)



回答2:


I believe the Vaadin grid (or table) component was designed having the table concept as a starting point. Hence you'd have a unified structure defined by the columns and display any number of same-type data elements, 1 per row. And as far as I know, up to 8.0.4, you can't rotate the structure.

Furthermore, from the user experience perspective, if you have multiple time periods, it'll be easier to scroll them vertically (with the mouse wheel) than horizontally, so I'd suggest discussing the possibility of displaying them just as you started, with the "month", "numberOfWorkers", "numberOfNewcomers" and "numberOfDismissals" columns, and supplying rows of MyData. This also makes it easier to sort, filter, add or edit selected items, whereas for the workaround below, you'd have to do something extra.

If for some reason that's not acceptable at all, you should be able to fake the feature you want with a bit of work (see below sample), but performance and usability wise, there's no guarantees... after all, this is not what it's been designed for.

Code

package com.example.grid;

import com.vaadin.data.ValueProvider;
import com.vaadin.ui.Grid;
import com.vaadin.ui.Notification;
import com.vaadin.ui.VerticalLayout;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.function.Function;

public class HorizontalGrid extends VerticalLayout {

    private static final String ROW_CAPTION = "row-caption";

    public HorizontalGrid() {
        // basic grid setup without column header
        Grid<HorizontalDisplayAdapter> grid = new Grid<>();
        grid.setSizeFull();
        grid.setSelectionMode(Grid.SelectionMode.NONE);
        grid.removeHeaderRow(0);

        // load some data from the DB or someplace else
        List<PeriodSummary> periods = loadPeriods();

        // add row headers
        grid.addColumn(HorizontalDisplayAdapter::getCaption).setId(ROW_CAPTION).setWidth(150);

        // add a column for each period
        for (int i = 0; i < periods.size(); i++) {
            // save the column index so we ca figure out what to edit later
            grid.addColumn(new AdapterValueProvider(i)).setId(String.valueOf(i)).setWidth(60);
        }

        // wrap the data in "horizontal display adapters"
        grid.setItems(
                new HorizontalDisplayAdapter("Period", periods, PeriodSummary::getPeriod),
                new HorizontalDisplayAdapter("Workers", periods, PeriodSummary::getWorkers),
                new HorizontalDisplayAdapter("Newcomers", periods, PeriodSummary::getNewcomers),
                new HorizontalDisplayAdapter("Dismissals", periods, PeriodSummary::getDismissals)
        );

        // retrieve the correct period summary to edit, based on the column that was clicked (unless it's the header)
        grid.addItemClickListener(event -> {
            if (!ROW_CAPTION.equals(event.getColumn().getId())) {
                Integer columnIndex = Integer.valueOf(event.getColumn().getId());
                Notification.show("Editing " + event.getItem().getSummary(columnIndex), Notification.Type.ERROR_MESSAGE);
            }
        });

        // freeze first column for scrolling purposes
        grid.setFrozenColumnCount(1);

        addComponent(grid);
        setSizeFull();
    }

    // generate some dummy data to simulate loading from the DB
    private List<PeriodSummary> loadPeriods() {
        Random random = new Random();
        ArrayList<PeriodSummary> periodSummaries = new ArrayList<>();
        for (int i = 0; i < 100; i++) {
            periodSummaries.add(new PeriodSummary(i, random.nextInt(100), random.nextInt(100), random.nextInt(100)));
        }
        return periodSummaries;
    }

    // adapter to display data in a "horizontal format"
    public class HorizontalDisplayAdapter {
        // row caption
        private final String caption;

        // periods for each column
        private final List<PeriodSummary> periods;

        // used for brevity, a class hierarchy is probably more elegant
        private Function<PeriodSummary, Integer> valueExtractor;

        public HorizontalDisplayAdapter(String caption, List<PeriodSummary> periods, Function<PeriodSummary, Integer> valueExtractor) {
            this.caption = caption;
            this.periods = periods;
            this.valueExtractor = valueExtractor;
        }

        public String getCaption() {
            return caption;
        }

        public PeriodSummary getSummary(int columnIndex) {
            return periods.get(columnIndex);
        }

        // extract the data for a certain column
        public Integer getValue(int columnIndex) {
            return valueExtractor.apply(periods.get(columnIndex));
        }
    }

    // basic bean
    public class PeriodSummary {
        int period;
        int workers;
        int newcomers;
        int dismissals;

        public PeriodSummary(int period, int workers, int newcomers, int dismissals) {
            this.period = period;
            this.workers = workers;
            this.newcomers = newcomers;
            this.dismissals = dismissals;
        }

        public int getPeriod() {
            return period;
        }

        public void setPeriod(int period) {
            this.period = period;
        }

        public int getWorkers() {
            return workers;
        }

        public void setWorkers(int workers) {
            this.workers = workers;
        }

        public int getNewcomers() {
            return newcomers;
        }

        public void setNewcomers(int newcomers) {
            this.newcomers = newcomers;
        }

        public int getDismissals() {
            return dismissals;
        }

        public void setDismissals(int dismissals) {
            this.dismissals = dismissals;
        }

        @Override
        public String toString() {
            return "PeriodSummary{" +
                    "period=" + period +
                    ", workers=" + workers +
                    ", newcomers=" + newcomers +
                    ", dismissals=" + dismissals +
                    '}';
        }
    }

    // value provider for the horizontal display adapters
    private class AdapterValueProvider implements ValueProvider<HorizontalDisplayAdapter, Integer> {
        // column index is used to retrieve data from the correct summary
        private int columnIndex;

        public AdapterValueProvider(int columnIndex) {
            this.columnIndex = columnIndex;
        }

        @Override
        public Integer apply(HorizontalDisplayAdapter horizontalDisplayAdapter) {
            return horizontalDisplayAdapter.getValue(columnIndex);
        }
    }
}

Result



来源:https://stackoverflow.com/questions/43074017/how-to-reverse-vaadin-grid

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!