Vaadin 8 - Сортировка элементов в ComboBox‹Integer›

У меня есть ComboBox типа Integer, который я настраиваю следующим образом:

Collection<Integer> cbItems = new HashSet<>();
for(Integer i = 100; i < 360; i+=5){
    cbItems.add(i);
}
ComboBox<Integer> cb = new ComboBox<>();
cb.setItems(cbItems);

Я создаю коллекцию целых чисел и заполняю ее определенными целочисленными значениями (100, 105, 110 и т. д.). Код компилируется, и ComboBox отображается в представлении.

Моя проблема в том, что элементы в ComboBox не отсортированы (или, лучше сказать, не отсортированы так, как я думал).

Скриншот реального поля со списком

Почему он повторно сортирует мою коллекцию Integer и как я могу это предотвратить?


person kscherrer    schedule 24.01.2018    source источник


Ответы (2)


Я бы порекомендовал вам заполнить компоненты vaadin, такие как ComboBox, с DataProvider. Позже это облегчит задачу.

Ваше собственное решение отлично работает, если элементы не добавлены позже в ComboBox в другом месте. Если элементы добавлены, возможно, потребуется выполнить Collections.sort() еще раз.

С небольшим изменением для использования DataProvider:

ListDataProvider<Integer> dp = new ListDataProvider<>(cbItems);
// the first param is function that returns the value to sort
// in case of Integer it is that Integer itself.
dp.setSortOrder(i -> {return i;}, SortDirection.ASCENDING);
ComboBox<Integer> combo = new ComboBox<>();
combo.setDataProvider(dp);

Теперь, если вы позже добавите предметы в комбо (через исходный Collection):

// add some items to see where they are sorted
cbItems.add(102);
cbItems.add(113);

эти элементы должны быть отсортированы в правильном месте в ComboBox.

Тогда рассмотрим немного более сложный пример. Если бы у вас был класс вроде:

@RequiredArgsConstructor
public class Wrapper {
   @Getter 
   private final Integer id;
   @Getter
   private final String name;
}

и вы хотели отсортировать его по убыванию имени, это было бы так (с тестовыми данными):

// generate some dymmy data
Collection<Wrapper> wrappers = new HashSet<>();
for(int i=1000; i<=2000; i+=150) {
   wrappers.add(new Wrapper(i, 
           "Rand"+ThreadLocalRandom.current().nextInt(5000, 6000)) );
}

ListDataProvider<Wrapper> dpWrappers = new ListDataProvider<>(wrappers);
// now function returns the name of the wrapper to sort as sort argument
dpWrappers.setSortOrder(wrapper -> {return wrapper.getName();}, 
                            SortDirection.DESCENDING);

ComboBox<Wrapper> comboWrappers = new ComboBox<>();
comboWrappers.setDataProvider(dpWrappers);
// remember to set this to have the name of wrapper in combo vaptions
// instead of the value of  Wrapper.toString();
comboWrappers.setItemCaptionGenerator( item -> {return item.getName();});
person pirho    schedule 24.01.2018
comment
Я видел ComboBox.setDataProvider и спрашивал себя, какой из них мне следует использовать. Потом я где-то прочитал, что нужно просто использовать .setItems() — так я и сделал. Теперь вы убедили меня использовать DataProviders, ваш ответ имеет смысл и был очень полезным. Спасибо. - person kscherrer; 25.01.2018

Хорошо, я понял:
я изменил коллекцию на список (ArrayList), поэтому я могу использовать Collections.sort(cbItems);

List<Integer> cbItems= new ArrayList<>();
for(Integer i = 100; i < 360; i+=5){
    cbItems.add(i);
}
Collections.sort(cbItems);

ComboBox<Integer> cb = new ComboBox<>();
cb.setItems(cbItems);

Теперь элементы отсортированы по возрастанию.

person kscherrer    schedule 24.01.2018