#java #arraylist #combobox
#java #arraylist #поле со списком
Вопрос:
У меня есть возможность для пользователя выбрать месяц. Я установил прослушиватель ItemListener
для своего выпадающего списка, который содержит список месяцев. У меня есть установленное условие, при котором, если пользователь выберет «Февраль», список дней будет только до 29, иначе «Апрель», «июнь» и так далее будут иметь 30 дней в моем выпадающем списке. Но когда я выбираю «Февраль», он работает нормально, но когда я выбираю другой месяц, я получаю сообщение об ошибке.
IndexOutOfBoundsException: Index: 30, Size: 29
Я знаю, что эта ошибка возникает из-за того, что другой месяц имеет индекс 30. Я немного запутался, должен ли я удалить содержимое ArrayList или ComboBox? Любая помощь, как я могу это устранить?
private ItemHandler handler = new ItemHandler();
ArrayList<String> daysList = new ArrayList<String>();
String[] daysObj = {"1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15",
"16", "17", "18", "19", "20", "21", "22", "23", "24", "25", "26", "27", "28", "29", "30", "31"};
DefaultComboBoxModel daysModel = new DefaultComboBoxModel(daysObj);
public AddEmployee()
{
setMonths();
setDays();
cbMonths.addItemListener(handler);
}
private void setDays()
{
for(int i = 0; i < daysObj.length; i )
{
daysList.add(daysObj[i]);
}
cbDays.setModel((ComboBoxModel)daysModel);
}
private class ItemHandler implements ItemListener
{
int removeDays[] = {29,30};//array
int remove[] = {30};
@Override
public void itemStateChanged(ItemEvent e)
{
if(e.getSource() == cbMonths)//Check where combobox occured.
{
if(cbMonths.getSelectedItem().equals("February"))
{
for(int i = removeDays.length-1; i >= 0; i--)
{
daysList.remove(removeDays[i]);//Remove given array from ArrayList using removeDays[]
System.out.println("NEW ELEMENT: " daysList);
}
for(String s : daysList)//Update ArrayList
{
cbDays.addItem(s);
System.out.println("NEW LIST OF ARRAY: " s);
}
}
else if(cbMonths.getSelectedItem().equals("April") || cbMonths.getSelectedItem().equals("June") ||
cbMonths.getSelectedItem().equals("September") || cbMonths.getSelectedItem().equals("November"))
{
for(int i = remove.length-1; i >= 0; i--)
{
daysList.remove(remove[i]);
System.out.println(daysList);
}
for(String a : daysList)//Update ArrayList
{
cbDays.addItem(a);
System.out.println("NEW LIST OF ARRAY: " a);
}
}
}
}
Я попробовал метод removeAllItems()
, но, похоже, он не работает. cbDays.removeAllItems();
Ответ №1:
Вместо выполнения сложных вычислений каждый раз, когда пользователь выбирает другой месяц (который трудно читать и подвержен ошибкам), лучше инициализировать некоторые статические модели, которые охватывают все случаи. Затем вашему обработчику с сохранением состояния нужно только выбрать правильную модель. Следующий пример основан на новом модном java 8 datetime API:
private static String[] initDays( int number )
{
String[] result = new String[ number];
for ( int i = 0; i < result.length; i )
{
result[i] = "" ( i 1);
}
return resu<
}
private static final String[] days28 = initDays( 28);
private static final String[] days29 = initDays( 29);
private static final String[] days30 = initDays( 30);
private static final String[] days31 = initDays( 31);
private static final ComboBoxModel<String> model28 = new DefaultComboBoxModel<>(days28);
private static final ComboBoxModel<String> model29 = new DefaultComboBoxModel<>(days29);
private static final ComboBoxModel<String> model30 = new DefaultComboBoxModel<>(days30);
private static final ComboBoxModel<String> model31 = new DefaultComboBoxModel<>(days31);
private static final Set<Month> month30 = EnumSet.of(
Month.FEBRUARY,
Month.APRIL,
Month.JUNE,
Month.SEPTEMBER,
Month.NOVEMBER
);
private static final Set<Month> month31 = EnumSet.of(
Month.JANUARY,
Month.MARCH,
Month.MAY,
Month.JULY,
Month.AUGUST,
Month.OCTOBER,
Month.DECEMBER
);
private JComboBox<String> cbMonths = new JComboBox<>();
private JComboBox<String> cbDays = new JComboBox<>();
public void itemStateChanged(ItemEvent e)
{
if(e.getSource() == cbMonths)//Check where combobox occured.
{
if(cbMonths.getSelectedItem().equals("February"))
{
Month selectedMonth = Month.valueOf( cbMonths.getItemAt( cbMonths.getSelectedIndex() ) );
if ( month31.contains( selectedMonth ) )
{
cbDays.setModel( model31 );
}
else if ( month30.contains( selectedMonth ) )
{
cbDays.setModel( model30 );
}
else
{
if ( Year.isLeap( Instant.now().getLong( ChronoField.YEAR ) ) )
{
cbDays.setModel( model29 );
}
else
{
cbDays.setModel( model28 );
}
}
}
}
}
Дальнейшим улучшением может быть использование cbMonth, который напрямую вводится с помощью перечисления месяцев, и предоставление средства визуализации ячеек, которое отображает месяц в языковом стандарте пользователя.
Комментарии:
1. Привет! @Heri Я все еще анализирую ваш код и уже пробовал его. В этом проекте я использовал GUI Builder. Должен ли я все еще вызывать
private JComboBox<String> cbMonths = new JComboBox<>();
? Потому что cbMonths и cbDays уже определены: D. Также я немного путаю вызовinitDays()
в конструкторе. Он должен быть объединен с объектом класса, верно?myObject.initDays();
?2. Строки, в которых я инициализирую cbMonths и cbDays, использовались в моем eclipse только для компиляции (и я скопировал его целиком сюда). Если у вас уже есть инициализированные экземпляры, просто используйте их.
3. initDays не вызывается в конструкторе. Оно статично и вызывается только один раз: когда класс загружается загрузчиком классов JVM.
4. Поскольку это уже определено в моем графическом интерфейсе, я прокомментировал,
private JComboBox<String> cbMonths = new JComboBox<>();
потому что это выдает ошибку, и попытался запустить ваш код, но это не меняет дни, когда я выбрал «Февраль».5. Извините, в моем наборе month30 есть ошибка: удалите там элемент FEBRUARY.
Ответ №2:
После инициализации через setDays()
daysList
содержит 31 элемент. Когда February
выбрано, два элемента с индексом 29
и 30
удаляются:
daysList.remove(removeDays[i])
daysList
теперь у 29
него есть элементы. Когда выбран другой месяц, один элемент с индексом 30
удаляется
daysList.remove(remove[i]);
Но dayslist
имеет только 29 элементов, поэтому IndexOutOfBoundsException
выбрасывается.
Поэтому одним из решений может быть повторная инициализация daysList
при каждом itemStateChanged
запуске.