In the new Vaadin Grid widget (alternative to venerable Table), how does one right-align numbers or other content in a column?
The simplest way I can think of is to define your own CSS classes and style generator, pretty much similar to what I'd had done when working with tables.
#Theme("mytheme")
#Widgetset("com.matritza.MyAppWidgetset")
public class MyUI extends UI {
#WebServlet(urlPatterns = "/*", name = "MyUIServlet", asyncSupported = true)
#VaadinServletConfiguration(ui = MyUI.class, productionMode = false)
public static class MyUIServlet extends VaadinServlet {
// meh, default stuff
}
#Override
protected void init(VaadinRequest vaadinRequest) {
final VerticalLayout layout = new VerticalLayout();
layout.setMargin(true);
setContent(layout);
// create a grid
Grid grid = new Grid("Grid test");
// create a specific container for the grid to hold our persons
BeanItemContainer<Person> container = new BeanItemContainer<>(Person.class);
grid.setContainerDataSource(container);
// define our own style generator
grid.setCellStyleGenerator(new Grid.CellStyleGenerator() {
#Override
public String getStyle(Grid.CellReference cellReference) {
if ("age".equals(cellReference.getPropertyId())) {
// when the current cell is number such as age, align text to right
return "rightAligned";
} else {
// otherwise, align text to left
return "leftAligned";
}
}
});
// generate some dummy data
for (int i = 0; i < 10; i++) {
container.addItem(new Person("Name " + i, "Surname " + i, i));
}
layout.addComponent(grid);
}
// basic class to populate the grid in a fast & simple way
public class Person {
private String name;
private String surname;
private int age;
private Person(String name, String surname, int age) {
this.name = name;
this.surname = surname;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSurname() {
return surname;
}
public void setSurname(String surname) {
this.surname = surname;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
}
And the basic CSS styles
#mixin mytheme {
#include valo;
// Insert your own theme rules here
.leftAligned {
text-align: left;
}
.rightAligned {
text-align: right;
}
}
And you should see something like
By the way, in Java 8 and later, the new Lambda syntax for that style generator would be:
grid.setCellStyleGenerator(( Grid.CellReference cellReference ) -> {
if ( "age".equals( cellReference.getPropertyId() ) ) {
// when the current cell is number such as age, align text to right
return "rightAligned";
} else {
// otherwise, align text to left
return "leftAligned";
}
});
One can also use already present styles like v-align-right, v-align-middle, etc. Just see what themes like Valo already contain, and extend existing themes only when needed.
Here's simple example how one could implement cell generator with regexp (matching one or multiple fields based on name of field)
public class RegexpCellStyleGenerator implements CellStyleGenerator {
private String regex = ".*"; // defaults all
String style = "v-align-right"; // default is here just as example
// special version useful only when one wants to style all fields inside grid
public RegexpCellStyleGenerator(String style) {
super();
this.style = style;
}
public RegexpCellStyleGenerator(String regex, String style) {
super();
this.regex = regex;
this.style = style;
}
#Override
public String getStyle(CellReference cellReference) {
String propertyId = cellReference.getPropertyId().toString();
if (propertyId.matches(regex)) {
return style;
}
return null;
}
and as this is only partially useful as most grids have multiple fields composite generator could be handy
public class CompositeCellStyleGenerator implements CellStyleGenerator {
List<CellStyleGenerator> generators = new ArrayList<>();
public CompositeCellStyleGenerator() {}
public void addCellStyleGenerator(CellStyleGenerator generator) {
generators.add(generator);
}
#Override
public String getStyle(CellReference cellReference) {
List<String> styles = new ArrayList<>();
for (CellStyleGenerator generator : generators) {
String style = generator.getStyle(cellReference);
if (style != null) {
styles.add(style);
}
}
if (!styles.isEmpty()) {
return styles.stream().collect(Collectors.joining(" "));
}
return null;
}
Composite generator joins all styles together and can be used like this. If there's multiple styles for one column both are applied.
RegexpCellStyleGenerator yearGenerator = new RegexpCellStyleGenerator("yearOfFoundation", "v-align-right");
RegexpCellStyleGenerator nameGenerator = new RegexpCellStyleGenerator("name", "v-align-center");
RegexpCellStyleGenerator nameGenerator2 = new RegexpCellStyleGenerator("name", "v-label-huge");
CompositeCellStyleGenerator compositeGenerator = new CompositeCellStyleGenerator();
compositeGenerator.addCellStyleGenerator(yearGenerator);
compositeGenerator.addCellStyleGenerator(nameGenerator);
compositeGenerator.addCellStyleGenerator(nameGenerator2);
grid.setCellStyleGenerator(compositeGenerator);
Note that composite generator can use generic generators like one with regexp definitions and more complex use case specific ones.
Hope this helps those who try to find easy way to style cells. Happy Experimenting.
Related
For example in the Select component the selected value is rendered as shown here. However when it comes to the ComboBox it is not rendered, only on the dropdown as shown here. I need to use the ComboBox because I need the search functionality, that is to have the item selected as they type in the value because there may be a lot of values. Ideally it would be great to merge the Select and ComboBox but barring that I'm wondering if there's a way to render the selected value.
You can't use an arbitrary Renderer, because the text input is, well, a text input. As noted in the comments below the question, what you're really after is an icon in front of the value of the input, and while there's no nice API in ComboBox for this, you can frankenstein together a solution using the prefix slot of the vaadin-text-field input. I've adapted an example using the Cookbook recipe here. Note that there's an enhancement request that would make handling prefix/suffix components in ComboBox easier: https://github.com/vaadin/flow-components/issues/1594
public class AboutView extends Div {
public AboutView() {
ComboBox<Person> comboBox = new ComboBox<>();
comboBox.setItems(getPersons());
// Renderer for the drop down
comboBox.setRenderer(new ComponentRenderer<Div, Person>(person -> {
Div container = new Div();
container.add(person.getIcon().create(), new Span(person.getName()));
return container;
}));
// on value change: either clear the prefix slot or create a new Icon there
comboBox.addValueChangeListener(e -> {
Person p = e.getValue();
if (p == null) {
PrefixUtil.clearSlot(comboBox, "prefix");
return;
}
PrefixUtil.setPrefixComponent(comboBox, p.getIcon().create());
});
comboBox.setItemLabelGenerator(Person::getName);
add(comboBox);
}
public List<Person> getPersons() {
List<Person> persons = new ArrayList<>();
Person person1 = new Person("Foo", VaadinIcon.ARROW_BACKWARD);
Person person2 = new Person("Bar", VaadinIcon.BAR_CHART);
Person person3 = new Person("Baz", VaadinIcon.PUZZLE_PIECE);
persons.add(person1);
persons.add(person2);
persons.add(person3);
return persons;
}
public static class Person {
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
private String name;
public VaadinIcon getIcon() {
return icon;
}
public void setIcon(VaadinIcon icon) {
this.icon = icon;
}
private VaadinIcon icon;
public Person(String name, VaadinIcon icon) {
this.name = name;
this.icon = icon;
}
}
public static class PrefixUtil {
private static Stream<Element> getElementsInSlot(HasElement target,
String slot) {
return target.getElement().getChildren()
.filter(child -> slot.equals(child.getAttribute("slot")));
}
public static void setPrefixComponent(Component target, Component component) {
clearSlot(target, "prefix");
if (component != null) {
component.getElement().setAttribute("slot", "prefix");
target.getElement().appendChild(component.getElement());
}
}
private static void clearSlot(Component target, String slot) {
getElementsInSlot(target, slot).collect(Collectors.toList())
.forEach(target.getElement()::removeChild);
}
private static Component getChildInSlot(HasElement target, String slot) {
Optional<Element> element = getElementsInSlot(target, slot).findFirst();
if (element.isPresent()) {
return element.get().getComponent().get();
}
return null;
}
public static Component getPrefixComponent(Component target) {
return getChildInSlot(target, "prefix");
}
}
}
I am playing around with vaadin 14.2.2 for testing purpose. However, I got to the first problem using Grid immediately. The Example from https://vaadin.com/docs/v14/flow/components/tutorial-flow-grid.html
List<Person> people = Arrays.asList(
new Person("Nicolaus Copernicus", 1543),
new Person("Galileo Galilei", 1564),
new Person("Johannes Kepler", 1571));
// Create a grid bound to the list
Grid<Person> grid = new Grid<>();
grid.setItems(people);
grid.addColumn(Person::getName).setHeader("Name");
grid.addColumn(Person::getYearOfBirth)
.setHeader("Year of birth");
layout.add(grid);
does not generate an output in the visualization. Also the hint in several GitHub issues to use
grid.setSizeFull();
does not solve this issue.
Has anybody any idea how to solve this?
The following snippet works for me on Vaadin 14.2.2 + Spring:
#Route("MainView")
public class MainView extends VerticalLayout {
public MainView() {
List<Person> people = Arrays.asList(
new Person("Nicolaus Copernicus", 1543),
new Person("Galileo Galilei", 1564),
new Person("Johannes Kepler", 1571));
// Create a grid bound to the list
Grid<Person> grid = new Grid<>();
grid.setItems(people);
grid.addColumn(Person::getName).setHeader("Name");
grid.addColumn(Person::getYearOfBirth).setHeader("Year of birth");
add(grid);
}
class Person {
String name;
Integer yearofbirth;
public Person(String name, Integer yearofbirth) {
this.name = name;
this.yearofbirth = yearofbirth;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getYearOfBirth() {
return yearofbirth;
}
public void setYearOfBirth(Integer yearofbirth) {
this.yearofbirth = yearofbirth;
}
}
}
I'm trying to export an Excel corresponding to a FilterTable using Vaadin TableExport. That Filtertable has some columns storing Dates and other class type elements, so I'm using setConverter function to print them as specific Strings:
filerTable.setConverter("dateColumn", dateConverter);
filerTable.setConverter("myClassColumn", myClassConverter);
dateConverter and myClassConverter are instances of some classes to print that column values as Strings.
The problem comes when I want to export the table as an Excel: That setConverter conversions are not being applied to the output file. For example, date cells are being exported as string ('42741,0080787037' instead of '06/01/17 0:11'). The code section to export the Excel file is:
ExcelExport exp = new ExcelExport(new CustomTableHolder(filerTable), "excel.xls");
exp.setRowHeaders(true);
exp.export();
Is there any way to export the table exactly as shown, having applied setConverter function?
Looking at the add-on sources, it seems that this feature is supported but 2 things have to happen in order for it to work:
you have to use a PropertyFormatTable (nothing fancy, just a wrapper over table for this custom purpose)
set the setUseTableFormatPropertyValue(true) on the ExcelExport
Code:
public class ExcelExportTableComponent extends VerticalLayout {
public ExcelExportTableComponent() {
// basic table configuration
Table table = new PropertyFormatTable();
BeanItemContainer<Person> itemContainer = new BeanItemContainer<>(Person.class);
table.setContainerDataSource(itemContainer);
table.setConverter("age", new AgeConverter());
// add some dummy data to the table
Random random = new Random();
for (int i = 0; i < 10; i++) {
itemContainer.addItem(new Person("Name " + i, "Surname " + i, random.nextInt(99) + 1));
}
// add components to the layout
addComponent(table);
addComponent(new Button("Export to excel", event -> {
ExcelExport excelExport = new ExcelExport(table);
excelExport.setUseTableFormatPropertyValue(true);
excelExport.excludeCollapsedColumns();
excelExport.setReportTitle("Demo Report");
excelExport.export();
}));
}
// basic bean for data binding
public static class Person {
private String name;
private String surname;
private int age;
public Person(String name, String surname, int age) {
this.name = name;
this.surname = surname;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSurname() {
return surname;
}
public void setSurname(String surname) {
this.surname = surname;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
// custom converter
private static class AgeConverter implements Converter<String, Integer> {
#Override
public Integer convertToModel(String value, Class<? extends Integer> targetType, Locale locale) throws ConversionException {
return Integer.valueOf(value.substring(0, value.indexOf(" years")));
}
#Override
public String convertToPresentation(Integer value, Class<? extends String> targetType, Locale locale) throws ConversionException {
return String.valueOf(value) + " years";
}
#Override
public Class<Integer> getModelType() {
return Integer.class;
}
#Override
public Class<String> getPresentationType() {
return String.class;
}
}
}
Output:
EDIT Recursion is required for the counter increment.
I have a GUI that adds entered fields to a ListView, but also adds the name of the object to a TableView beside it and displays four substring counts. They are Plant objects, and it's supposed to display in the ListView (which it does), and then display the name with each occurrence of a certain substring:
See here:
I don't understand what I'm missing, because in my addButtonClick method, I call my recursive method. The logic seems correct to me in the method, so I must be missing something in my Integer properties, or a constructor.
Here is the method in the Controller for the add button click. There is a combo box where a user can choose Flower, Fungus, Weed, or Herb. And when the user clicks a respective plant type, respective radio buttons appear that are related to certain traits. All of that works. I will show the Flower section of code:
/*
Adds respective plant type and resets controls
*/
public void handleAddButtonClick(ActionEvent event) {
if (idInput != null && nameInput != null & colorInput != null) {
if (plantType.getValue().equals("Flower")) {
Flower flower = new Flower(ID, idNum, name, color, smell, thorns, edible, poisonous, flavor, medicine, seasonal);
flower.setID(idInput.getText());
flower.setName(nameInput.getText());
flower.setColor(colorInput.getText());
flower.setSmell(scentedRadio.isSelected());
flower.setThorns(thornyRadio.isSelected());
observablePlantList.add(flower);
//this is where the table information gets added.
//it adds it, just displays 0's.
flower.setPlantName(nameInput.getText());
Plant.substringCounter(name, "e"); //tried flower instead
Plant.substringCounter(name, "ar");//of Plant. still nothing.
Plant.substringCounter(name, "er");
Plant.substringCounter(name, "o");
observableAnalysisList.add(flower);
//just doing some debug printing. this prints 0
System.out.println(Plant.substringCounter(name, "e"));
//more debugging. this prints fine because of toString() method
System.out.println(flower);
Here is the relevant code in the main class and the Flower class:
//Plant Table properties ("e", "o", "ar", "er")
public StringProperty plantName = new SimpleStringProperty(this, "plantName", "");
public String getPlantName() {return plantName.get(); }
public StringProperty plantNameProperty() {return plantName; }
public void setPlantName(String plantName) {this.plantName.set(plantName); }
public IntegerProperty countLetterE = new SimpleIntegerProperty(this, "countLetterE", 0);
public int getLetterE() {return countLetterE.get();}
public IntegerProperty eProperty() {return countLetterE; }
public void setCountLetterE(int countLetterE) {this.countLetterE.set(countLetterE);}
public IntegerProperty countLetterO = new SimpleIntegerProperty(this, "countLetterO", 0);
public int getLetterO() {return countLetterO.get(); }
public IntegerProperty oProperty() {return countLetterO; }
public void setCountLetterO(int countLetterO) {this.countLetterO.set(countLetterO);}
public IntegerProperty countLetterER = new SimpleIntegerProperty(this, "countLetterER", 0);
public int getLetterER() {return countLetterER.get(); }
public IntegerProperty erProperty() {return countLetterER; }
public void setCountLetterER(int countLetterER) {this.countLetterER.set(countLetterER);}
public IntegerProperty countLetterAR = new SimpleIntegerProperty(this, "countLetterAR", 0);
public int getLetterAR() {return countLetterAR.get(); }
public IntegerProperty arProperty() {return countLetterAR; }
public void setCountLetterAR(int countLetterAR) {this.countLetterAR.set(countLetterAR);}
Recursive method:
public static int substringCounter(String plantName, String letters) {
plantName = plantName.toLowerCase();
if(plantName.isEmpty()) {
return 0;
}
if(plantName.indexOf(letters) == -1) {
return 0;
}
return 1 + substringCounter(plantName.substring(plantName.indexOf(letters) + 1), letters);
}
//toString method for Plant class to display in ListView. Works fine.
public String toString() {
return "ID: " + this.ID + "-" + this.idNum + ", Name: " + this.name + ", Color: " + this.color;
}
}
Flower class
public class Flower extends Plant {
public Flower(String ID, int idNum, String name, String color, boolean smell, boolean thorns, boolean edible, boolean poisonous, boolean flavor, boolean medicine, boolean seasonal) {
super(ID, idNum, name, color, smell, thorns, edible, poisonous, flavor, medicine, seasonal);
}
public void setSmell(boolean smell) {
this.smell = smell;
}
public void setThorns(boolean thorns) {
this.thorns = thorns;
}
//toString method for the ListView only. All works fine here
public String toString() {
return super.toString() + ", Scent? " + this.smell + ", Thorns? " + this.thorns;
}
}
I sincerely hope I either 1) gave you enough information, or 2) didn't give you too much information. Thank you all for any help offered.
You are invoking a static method on a string and return a number which effectively results in absolutely nothing when you call it like that:
Plant.substringCounter(name, "e");
You need to modify a property if you want some "action" or at least process the result that's being returned by substringCounter.
Besides, I have no idea why you use recursion. This does the same:
String text = "dandelion";
String search = "d";
int count = 0;
int pos = 0;
if (!search.isEmpty()) {
while ((pos = text.indexOf(search, pos)) != -1) {
count++;
pos++;
}
}
System.out.println(count);
Basically something like this:
import javafx.application.Application;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.scene.layout.HBox;
import javafx.stage.Stage;
public class Main extends Application {
#Override
public void start(Stage primaryStage) {
HBox box = new HBox();
box.setSpacing(10);
TextField sourceTextField = new TextField( "Dandelion");
Label result = new Label();
TextField searchTextField = new TextField();
// add listener for counting the number of substrings
searchTextField.textProperty().addListener(new ChangeListener<String>() {
#Override
public void changed(ObservableValue<? extends String> observable, String oldValue, String newValue) {
String sourceText = sourceTextField.getText().toLowerCase();
String searchText = newValue.toLowerCase();
int count = 0;
int pos = 0;
if( !searchText.isEmpty()) {
while( (pos = sourceText.indexOf( searchText, pos)) != -1) {
count++;
pos++;
}
}
result.setText( String.valueOf(count));
}
});
box.getChildren().addAll( new Label( "Search:"), searchTextField, new Label( "Text:"), sourceTextField, new Label( "Count:"), result);
Scene scene = new Scene(box, 600, 200);
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
Or using your recursive method (you also need to check letters for empty string by the way):
import javafx.application.Application;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.scene.layout.HBox;
import javafx.stage.Stage;
public class Main extends Application {
#Override
public void start(Stage primaryStage) {
HBox box = new HBox();
box.setSpacing(10);
TextField sourceTextField = new TextField( "Dandelion");
Label result = new Label();
TextField searchTextField = new TextField();
searchTextField.textProperty().addListener(new ChangeListener<String>() {
#Override
public void changed(ObservableValue<? extends String> observable, String oldValue, String newValue) {
String sourceText = sourceTextField.getText().toLowerCase();
String searchText = newValue.toLowerCase();
result.setText( String.valueOf( substringCounter( sourceText, searchText)));
}
});
box.getChildren().addAll( new Label( "Search:"), searchTextField, new Label( "Text:"), sourceTextField, new Label( "Count:"), result);
Scene scene = new Scene(box, 600, 200);
primaryStage.setScene(scene);
primaryStage.show();
}
public static int substringCounter(String plantName, String letters) {
plantName = plantName.toLowerCase();
if(letters.isEmpty()) {
return 0;
}
if(plantName.isEmpty()) {
return 0;
}
if(plantName.indexOf(letters) == -1) {
return 0;
}
return 1 + substringCounter(plantName.substring(plantName.indexOf(letters) + 1), letters);
}
public static void main(String[] args) {
launch(args);
}
}
Instead of setting the label like I did in the example you of course have to change your integer properties.
I am using BeanItemContainer for my comboboxes to satisfy key-value pairs.
#SuppressWarnings("serial")
public class ComboBoxItem implements Serializable {
private String id;
private String description;
public ComboBoxItem(final String id, final String description) {
this.id = id;
this.description = description;
}
public final void setId(final String id) {
this.id = id;
}
public final void setDescription(final String description) {
this.description = description;
}
public final String getId() {
return id;
}
public final String getDescription() {
return description;
}
}
I created a sample combobox as below
List<ComboBoxItem> lstAuctionDateList = new ArrayList<ComboBoxItem>();
lstAuctionDateList.add(new ComboBoxItem("all", "All"));
BeanItemContainer<ComboBoxItem> auctionDateItems = new BeanItemContainer<ComboBoxItem>(ComboBoxItem.class,
lstAuctionDateList);
final ComboBox cbAuctionDate = new ComboBox("Auction Date", auctionDateItems);
cbAuctionDate.addStyleName("small");
cbAuctionDate.setNullSelectionAllowed(false);
cbAuctionDate.setTextInputAllowed(false);
cbAuctionDate.setItemCaptionPropertyId("description");
cbAuctionDate.addValueChangeListener(new ValueChangeListener() {
public void valueChange(final ValueChangeEvent event) {
if (cbAuctionDate.getValue() != null) {
System.out.println(((ComboBoxItem) cbAuctionDate.getValue()).getId());
System.out.println(((ComboBoxItem) cbAuctionDate.getValue()).getDescription());
}
}
});
It is fine but I can't select any of combobox items by using below codes
cbAuctionDate.select("all");
cbAuctionDate.select("All");
cbAuctionDate.setValue("all");
cbAuctionDate.setValue("All");
What am I wrong ? How can I select my comboxes by programmatically ?
when using a (bean) container and adding items, the identity of the item itself is used as the itemId in the container. E.g. cbActionDate.select(lstAuctionDateList[0]) should work.
You either have yo make your objects immutable or use ways to tell the container, what it has to use for an id (E.g. setBeanIdProperty("id") or setBeanIdResolver).
Making the object immutable should be easy right now (make the class and the private attributes final, drop the setters and let your IDE generate equals and hashCode for you)
You don't need the cbAuctionDate.addItem("All") call, you already have such a item in your collection
I would try it that way:
List<ComboBoxItem> lstAuctionDateList = new ArrayList<ComboBoxItem>();
ComboBoxItem allItems= new ComboBoxItem("all", "All");
lstAuctionDateList.add(allItems);
....
...
cbAuctionDate.select(allItems);
Now I created custom ComboBox component for my problem
public class ComboBox extends CustomComponent implements Serializable {
private com.vaadin.ui.ComboBox comboBox;
private BeanItemContainer<ComboBoxItem> entries = new BeanItemContainer<ComboBoxItem>(ComboBoxItem.class);
public ComboBox() {
comboBox = new com.vaadin.ui.ComboBox();
comboBox.addStyleName("small");
comboBox.setNullSelectionAllowed(false);
comboBox.setTextInputAllowed(false);
setCompositionRoot(comboBox);
}
public ComboBox(final String caption) {
comboBox = new com.vaadin.ui.ComboBox();
comboBox.addStyleName("small");
comboBox.setNullSelectionAllowed(false);
comboBox.setTextInputAllowed(false);
setCaption(caption);
setCompositionRoot(comboBox);
}
public ComboBox(final String caption, final List<ComboBoxItem> items) {
comboBox = new com.vaadin.ui.ComboBox();
comboBox.addStyleName("small");
comboBox.setNullSelectionAllowed(false);
comboBox.setTextInputAllowed(false);
setCaption(caption);
if (items != null && items.size() > 0) {
entries.addAll(items);
comboBox.setContainerDataSource(entries);
comboBox.setItemCaptionMode(ItemCaptionMode.PROPERTY);
addItems(entries);
comboBox.select(items.get(0));
comboBox.setItemCaptionPropertyId("description");
}
setCompositionRoot(comboBox);
}
public final void addItems(final List<ComboBoxItem> items) {
if (items != null && items.size() > 0) {
entries.addAll(items);
comboBox.setContainerDataSource(entries);
comboBox.setItemCaptionMode(ItemCaptionMode.PROPERTY);
addItems(entries);
comboBox.select(items.get(0));
comboBox.setItemCaptionPropertyId("description");
}
}
private void addItems(final BeanItemContainer<ComboBoxItem> items) {
comboBox.addItems(items);
}
public final void addItem(final ComboBoxItem item) {
if (item != null) {
comboBox.setContainerDataSource(entries);
comboBox.addItem(item);
comboBox.setItemCaptionPropertyId("description");
}
}
public final void selectByIndex(final int index) {
Object[] ids = comboBox.getItemIds().toArray();
comboBox.select(((ComboBoxItem) ids[index]));
}
public final void selectById(final String id) {
Object[] ids = comboBox.getItemIds().toArray();
for (int i = 0; i < ids.length; i++) {
if (((ComboBoxItem) ids[i]).getId().equals(id)) {
selectByIndex(i);
break;
}
}
}
public final void selectByItemText(final String description) {
Object[] ids = comboBox.getItemIds().toArray();
for (int i = 0; i < ids.length; i++) {
if (((ComboBoxItem) ids[i]).getDescription().equals(description)) {
selectByIndex(i);
break;
}
}
}
public final int getItemCount() {
return comboBox.getItemIds().toArray().length;
}
public final String getSelectedId() {
return ((ComboBoxItem) comboBox.getValue()).getId();
}
public final String getSelectedItemText() {
return ((ComboBoxItem) comboBox.getValue()).getDescription();
}
public final void addValueChangeListener(final ValueChangeListener listener) {
comboBox.addValueChangeListener(listener);
}
}
and below is test codes
final ComboBox combo = new ComboBox("My ComboBox");
combo.addItem(new ComboBoxItem("all", "All"));
// Add with list
List<ComboBoxItem> items = new ArrayList<ComboBoxItem>();
items.add(new ComboBoxItem("one", "One"));
items.add(new ComboBoxItem("two", "Two"));
items.add(new ComboBoxItem("three", "Three"));
combo.addItems(items);
combo.addItem(new ComboBoxItem("four", "Four"));
combo.addItem(new ComboBoxItem("five", "five"));
combo.selectByIndex(3);
combo.addValueChangeListener(new ValueChangeListener() {
public void valueChange(final ValueChangeEvent event) {
System.out.println(combo.getSelectedId() + " --- " + combo.getSelectedItemText());
}
});