2017-01-10 11 views
0

Я пытаюсь создать TableView, который содержит Student объектов и Classroom объектов. Теперь я хочу иметь ChoiceBox для обмена Students с одного Classroom на другой. .Проблема с созданием JFX TableView с настраиваемой редактируемой ячейкой

Вот код

public class ChoiceBoxCell extends TableCell<Student, Classroom> { 


    ChoiceBox<Classroom> classroomChoiceBox = new ChoiceBox<>(); 

    public ChoiceBoxCell(ObservableList<Classroom> classroomObservableList) { 
     ObservableList<Classroom> classroomObservableListList = classroomObservableList; 
     classroomChoiceBox.setItems(classroomObservableListList); 

     classroomChoiceBox.getSelectionModel().selectedIndexProperty().addListener((obs, oldValue, newValue) -> { 
      Classroom value = classroomChoiceBox.getItems().get((int) newValue); 
      classroomChoiceBox.setValue(value); 
      processEdit(value); 
     }); 
    } 
    private void processEdit(Classroom value) { 
     commitEdit(value); 
     classroomChoiceBox.setValue(value); 
     setGraphic(classroomChoiceBox); 
    } 

    @Override 
    public void cancelEdit() { 
     super.cancelEdit(); 
     setGraphic(classroomChoiceBox); 
    } 

    @Override 
    public void commitEdit(Classroom value) { 
     super.commitEdit(value); 
     classroomChoiceBox.setValue(value); 
     setGraphic(classroomChoiceBox); 
    } 

    @Override 
    public void startEdit() { 
     super.startEdit(); 
     Classroom value = getItem(); 
     if (value != null) { 
      classroomChoiceBox.setValue(value); 
      setGraphic(classroomChoiceBox); 
     } 
    } 

    @Override 
    protected void updateItem(Classroom item, boolean empty) { 
     super.updateItem(item, empty); 
     if (item == null || empty) { 
      classroomChoiceBox.setValue(item); 
      setGraphic(classroomChoiceBox); 
     } else { 
      classroomChoiceBox.setValue(item); 
      setGraphic(classroomChoiceBox); 
     } 
    } 
} 

В моем TableView классе

Список classroomList = новый ClassroomDao() GetAllClasses(); Класс ObservableListObservableList = FXCollections.observableArrayList (classroomList);

classroomNameColumn.setPrefWidth(columnSize); 
classroomNameColumn.setCellValueFactory(cdf -> cdf.getValue().classroomProperty()); 
classroomNameColumn.setCellFactory(column -> new ChoiceBoxCell(classroomObservableList)); 
classroomNameColumn.setEditable(true); 

Я получаю следующее исключение

Exception in thread "JavaFX Application Thread" java.lang.ArrayIndexOutOfBoundsException: -1 
at java.util.ArrayList.elementData(ArrayList.java:418) 
at java.util.ArrayList.get(ArrayList.java:431) 
at com.sun.javafx.collections.ObservableListWrapper.get(ObservableListWrapper.java:89) 
at view.adminAccess.studentOverview.ChoiceBoxCell.lambda$new$0(ChoiceBoxCell.java:20) 
at com.sun.javafx.binding.ExpressionHelper$Generic.fireValueChangedEvent(ExpressionHelper.java:361) 
at com.sun.javafx.binding.ExpressionHelper.fireValueChangedEvent(ExpressionHelper.java:81) 
at javafx.beans.property.ReadOnlyIntegerWrapper$ReadOnlyPropertyImpl.fireValueChangedEvent(ReadOnlyIntegerWrapper.java:176) 
at javafx.beans.property.ReadOnlyIntegerWrapper.fireValueChangedEvent(ReadOnlyIntegerWrapper.java:142) 
at javafx.beans.property.IntegerPropertyBase.markInvalid(IntegerPropertyBase.java:113) 
at javafx.beans.property.IntegerPropertyBase.set(IntegerPropertyBase.java:147) 
at javafx.scene.control.SelectionModel.setSelectedIndex(SelectionModel.java:68) 
at javafx.scene.control.SingleSelectionModel.select(SingleSelectionModel.java:114) 
at javafx.scene.control.ChoiceBox$4.invalidated(ChoiceBox.java:331) 
at javafx.beans.property.ObjectPropertyBase.markInvalid(ObjectPropertyBase.java:111) 
at javafx.beans.property.ObjectPropertyBase.set(ObjectPropertyBase.java:146) 
at javafx.scene.control.ChoiceBox.setValue(ChoiceBox.java:336) 
at view.adminAccess.studentOverview.ChoiceBoxCell.updateItem(ChoiceBoxCell.java:58) 
at view.adminAccess.studentOverview.ChoiceBoxCell.updateItem(ChoiceBoxCell.java:10) 
at javafx.scene.control.TableCell.updateItem(TableCell.java:639) 
at javafx.scene.control.TableCell.indexChanged(TableCell.java:468) 
at javafx.scene.control.IndexedCell.updateIndex(IndexedCell.java:116) 
at com.sun.javafx.scene.control.skin.TableRowSkinBase.requestCellUpdate(TableRowSkinBase.java:659) 
at com.sun.javafx.scene.control.skin.TableRowSkinBase.lambda$init$497(TableRowSkinBase.java:159) 
at com.sun.javafx.binding.ExpressionHelper$SingleInvalidation.fireValueChangedEvent(ExpressionHelper.java:137) 
at com.sun.javafx.binding.ExpressionHelper.fireValueChangedEvent(ExpressionHelper.java:81) 
at javafx.beans.property.ObjectPropertyBase.fireValueChangedEvent(ObjectPropertyBase.java:105) 
at javafx.beans.property.ObjectPropertyBase.markInvalid(ObjectPropertyBase.java:112) 
at javafx.beans.property.ObjectPropertyBase.set(ObjectPropertyBase.java:146) 
at javafx.scene.control.Cell.setItem(Cell.java:403) 
at javafx.scene.control.Cell.updateItem(Cell.java:670) 
at javafx.scene.control.TableRow.updateItem(TableRow.java:268) 
at javafx.scene.control.TableRow.indexChanged(TableRow.java:225) 
at javafx.scene.control.IndexedCell.updateIndex(IndexedCell.java:116) 
at com.sun.javafx.scene.control.skin.VirtualFlow.releaseCell(VirtualFlow.java:1807) 
at com.sun.javafx.scene.control.skin.VirtualFlow.getCellLength(VirtualFlow.java:1881) 
at com.sun.javafx.scene.control.skin.VirtualFlow.computeViewportOffset(VirtualFlow.java:2528) 
at com.sun.javafx.scene.control.skin.VirtualFlow.layoutChildren(VirtualFlow.java:1189) 
at javafx.scene.Parent.layout(Parent.java:1079) 
at javafx.scene.Parent.layout(Parent.java:1085) 
at javafx.scene.Parent.layout(Parent.java:1085) 
at javafx.scene.Parent.layout(Parent.java:1085) 
at javafx.scene.Parent.layout(Parent.java:1085) 
at javafx.scene.Scene.doLayoutPass(Scene.java:552) 
at javafx.scene.Scene$ScenePulseListener.pulse(Scene.java:2397) 
at com.sun.javafx.tk.Toolkit.lambda$runPulse$31(Toolkit.java:355) 
at java.security.AccessController.doPrivileged(Native Method) 
at com.sun.javafx.tk.Toolkit.runPulse(Toolkit.java:354) 
at com.sun.javafx.tk.Toolkit.firePulse(Toolkit.java:381) 
at com.sun.javafx.tk.quantum.QuantumToolkit.pulse(QuantumToolkit.java:510) 
at com.sun.javafx.tk.quantum.PaintCollector.liveRepaintRenderJob(PaintCollector.java:320) 
at com.sun.javafx.tk.quantum.GlassViewEventHandler$ViewEventNotification.run(GlassViewEventHandler.java:788) 
at com.sun.javafx.tk.quantum.GlassViewEventHandler$ViewEventNotification.run(GlassViewEventHandler.java:749) 
at java.security.AccessController.doPrivileged(Native Method) 
at com.sun.javafx.tk.quantum.GlassViewEventHandler.lambda$handleViewEvent$369(GlassViewEventHandler.java:828) 
at com.sun.javafx.tk.quantum.QuantumToolkit.runWithoutRenderLock(QuantumToolkit.java:389) 
at com.sun.javafx.tk.quantum.GlassViewEventHandler.handleViewEvent(GlassViewEventHandler.java:827) 
at com.sun.glass.ui.View.handleViewEvent(View.java:539) 
at com.sun.glass.ui.View.notifyResize(View.java:875) 
at com.sun.glass.ui.win.WinWindow._setBounds(Native Method) 
at com.sun.glass.ui.Window.setBounds(Window.java:572) 
at com.sun.javafx.tk.quantum.WindowStage.setBounds(WindowStage.java:318) 
at javafx.stage.Window$TKBoundsConfigurator.apply(Window.java:1274) 
at javafx.stage.Window$TKBoundsConfigurator.pulse(Window.java:1290) 
at com.sun.javafx.tk.Toolkit.lambda$runPulse$31(Toolkit.java:355) 
at java.security.AccessController.doPrivileged(Native Method) 
at com.sun.javafx.tk.Toolkit.runPulse(Toolkit.java:354) 
at com.sun.javafx.tk.Toolkit.firePulse(Toolkit.java:378) 
at com.sun.javafx.tk.quantum.QuantumToolkit.pulse(QuantumToolkit.java:510) 
at com.sun.javafx.tk.quantum.QuantumToolkit.pulse(QuantumToolkit.java:490) 
at com.sun.javafx.tk.quantum.QuantumToolkit.lambda$runToolkit$405(QuantumToolkit.java:319) 
at com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:95) 
at com.sun.glass.ui.win.WinApplication._runLoop(Native Method) 
at com.sun.glass.ui.win.WinApplication.lambda$null$149(WinApplication.java:191) 
at java.lang.Thread.run(Thread.java:745) 

This как это выглядит. Кажется, что последняя ячейка пытается подогнать каждую строку в таблице с помощью ChoiceBox.

Как я могу ограничить это только строками, в которых есть данные?

EDIT: дополнительный выпуск

Часть кода я использую сейчас.

classroomChoiceBox.getSelectionModel().selectedItemProperty().addListener((obs, oldValue, newValue) -> { 
     if (newValue != null) { 
      processEdit(newValue); 
     } 
    }); 

@Override 
public void commitEdit(Classroom value) { // always gets executed 
    super.commitEdit(value); 
    Student student = (Student) getTableRow().getItem(); 
    student.setClassroom(value); 
    new StudentDao().updateStudent(student); // students get updated on creation of the table 
    classroomChoiceBox.setValue(value); 
    setGraphic(classroomChoiceBox); 
} 

Вопрос заключается в том, что каждый Student обновляется при создании таблицы.

+0

Опубликовать полную трассировку стека в своем вопросе. –

+0

@James_D Отредактировано, это все, что он показывает. –

+0

И предположительно строка 20 является «Классным классом = classroomChoiceBox.getSelectionModel() ...'? –

ответ

0

Выбранный индекс в модели выбора установлен в -1, если ничего не выбрано (см. docs). Поскольку -1 не является допустимым индексом в списке, вы должны проверить для этого случая:

classroomChoiceBox.getSelectionModel().selectedIndexProperty().addListener((obs, oldValue, newValue) -> { 
    int index = newValue.intValue(); 
    if (index >= 0) { 
     Classroom value = classroomChoiceBox.getItems().get(index); 

     // what is the point of the next line? 
     // surely this is the value in the choice box already??? 
     classroomChoiceBox.setValue(value); 

     processEdit(value); 
    } 
}); 

Конечно, это может быть проще просто получить значение непосредственно из модели выбора, вместо того, чтобы его индекс:

classroomChoiceBox.getSelectionModel().selectedItemProperty().addListener((obs, oldValue, newValue) -> { 
    if (newValue != null) { /* don't know if you care if this is null... */ 
     processEdit(newValue); 
    } 
}); 

причина вы видите выбор коробки в пустые ячейки в том, что вы явно установить графический в поле выбора в пустых клетках, в методе клетки updateItem. Я предполагаю (поскольку блок if идентичен блоку else), что это просто некоторая ошибка копирования и вставки.

+0

Отлично, спасибо большое. Первое решение работает отлично (второе не так, как newValue - это «Number», и мне нужен объект «Classroom». В любом случае, это не имеет значения, поскольку первый работает без проблем). –

+0

@ HonzaŠtefánik, видимо, вы не правильно прочитали ответ. 'NewValue' является' Classroom', а не 'Number', если вы измените его с' selectedIndexProperty' на 'selectedItemProperty'. –

+0

О, оказывается, мне даже не нужен 'if (index> = 0)'. Вероятно, это был неправильный 'setGraphic'. И да, мне не нужно «classroomChoiceBox.setValue (значение);». Еще раз спасибо. –