如何正确将空项目添加到JavaFX的ComboBox

时间:2018-08-04 22:09:28

标签: java javafx-8

如何将null项目正确添加到JavaFX的ComboBox<T>

ComboBox

我已经尝试过了:

@FXML 
private ComboBox<Producto> comboProductos;
private ObservableList<Producto> productos;

productos = FXCollections.observableArrayList(ProductoDAO.obtenerProductos());
productos.add(0, null);
comboProductos.setItems(productos);

它可以工作,但是在选择null项时会抛出此异常

java.lang.IndexOutOfBoundsException: null
at com.sun.javafx.scene.control.ReadOnlyUnbackedObservableList.subList(ReadOnlyUnbackedObservableList.java:136) ~[jfxrt.jar:?]
at javafx.collections.ListChangeListener$Change.getAddedSubList(ListChangeListener.java:242) ~[jfxrt.jar:?]
at com.sun.javafx.scene.control.behavior.ListViewBehavior.lambda$new$177(ListViewBehavior.java:269) ~[jfxrt.jar:?]
at javafx.collections.WeakListChangeListener.onChanged(WeakListChangeListener.java:88) ~[jfxrt.jar:?]
at com.sun.javafx.collections.ListListenerHelper$Generic.fireValueChangedEvent(ListListenerHelper.java:329) ~[jfxrt.jar:?]
at com.sun.javafx.collections.ListListenerHelper.fireValueChangedEvent(ListListenerHelper.java:73) ~[jfxrt.jar:?]
at com.sun.javafx.scene.control.ReadOnlyUnbackedObservableList.callObservers(ReadOnlyUnbackedObservableList.java:75) ~[jfxrt.jar:?]
at javafx.scene.control.MultipleSelectionModelBase.clearAndSelect(MultipleSelectionModelBase.java:378) ~[jfxrt.jar:?]
at javafx.scene.control.ListView$ListViewBitSetSelectionModel.clearAndSelect(ListView.java:1403) ~[jfxrt.jar:?]
at com.sun.javafx.scene.control.behavior.CellBehaviorBase.simpleSelect(CellBehaviorBase.java:256) ~[jfxrt.jar:?]
at com.sun.javafx.scene.control.behavior.CellBehaviorBase.doSelect(CellBehaviorBase.java:220) ~[jfxrt.jar:?]
at com.sun.javafx.scene.control.behavior.CellBehaviorBase.mousePressed(CellBehaviorBase.java:150) ~[jfxrt.jar:?]
at com.sun.javafx.scene.control.skin.BehaviorSkinBase$1.handle(BehaviorSkinBase.java:95) ~[jfxrt.jar:?]
at com.sun.javafx.scene.control.skin.BehaviorSkinBase$1.handle(BehaviorSkinBase.java:89) ~[jfxrt.jar:?]
at com.sun.javafx.event.CompositeEventHandler$NormalEventHandlerRecord.handleBubblingEvent(CompositeEventHandler.java:218) ~[jfxrt.jar:?]
at com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(CompositeEventHandler.java:80) ~[jfxrt.jar:?]
at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:238) ~[jfxrt.jar:?]
at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:191) ~[jfxrt.jar:?]
at com.sun.javafx.event.CompositeEventDispatcher.dispatchBubblingEvent(CompositeEventDispatcher.java:59) ~[jfxrt.jar:?]
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:58) ~[jfxrt.jar:?]
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114) ~[jfxrt.jar:?]
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56) ~[jfxrt.jar:?]
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114) ~[jfxrt.jar:?]
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56) ~[jfxrt.jar:?]
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114) ~[jfxrt.jar:?]
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56) ~[jfxrt.jar:?]
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114) ~[jfxrt.jar:?]
at com.sun.javafx.event.EventUtil.fireEventImpl(EventUtil.java:74) ~[jfxrt.jar:?]
at com.sun.javafx.event.EventUtil.fireEvent(EventUtil.java:54) ~[jfxrt.jar:?]
at javafx.event.Event.fireEvent(Event.java:198) ~[jfxrt.jar:?]
at javafx.scene.Scene$MouseHandler.process(Scene.java:3757) ~[jfxrt.jar:?]
at javafx.scene.Scene$MouseHandler.access$1500(Scene.java:3485) ~[jfxrt.jar:?]
at javafx.scene.Scene.impl_processMouseEvent(Scene.java:1762) ~[jfxrt.jar:?]
at javafx.scene.Scene$ScenePeerListener.mouseEvent(Scene.java:2494) ~[jfxrt.jar:?]
at com.sun.javafx.tk.quantum.GlassViewEventHandler$MouseEventNotification.run(GlassViewEventHandler.java:394) ~[jfxrt.jar:?]
at com.sun.javafx.tk.quantum.GlassViewEventHandler$MouseEventNotification.run(GlassViewEventHandler.java:295) ~[jfxrt.jar:?]
at java.security.AccessController.doPrivileged(Native Method) ~[?:1.8.0_172]
at com.sun.javafx.tk.quantum.GlassViewEventHandler.lambda$handleMouseEvent$353(GlassViewEventHandler.java:432) ~[jfxrt.jar:?]
at com.sun.javafx.tk.quantum.QuantumToolkit.runWithoutRenderLock(QuantumToolkit.java:389) ~[jfxrt.jar:?]
at com.sun.javafx.tk.quantum.GlassViewEventHandler.handleMouseEvent(GlassViewEventHandler.java:431) ~[jfxrt.jar:?]
at com.sun.glass.ui.View.handleMouseEvent(View.java:555) ~[jfxrt.jar:?]
at com.sun.glass.ui.View.notifyMouse(View.java:937) ~[jfxrt.jar:?]
at com.sun.glass.ui.win.WinApplication._runLoop(Native Method) ~[jfxrt.jar:?]
at com.sun.glass.ui.win.WinApplication.lambda$null$147(WinApplication.java:177) ~[jfxrt.jar:?]
at java.lang.Thread.run(Thread.java:748) [?:1.8.0_172]

3 个答案:

答案 0 :(得分:1)

下面是一个示例代码,它向null添加了ComboBox。该代码运行时没有任何运行时错误:

import javafx.application.Application;
import javafx.scene.Scene;
import javafx.stage.Stage;
import javafx.scene.control.*;
import javafx.scene.layout.HBox;
import javafx.geometry.Pos;
import javafx.collections.*;
public class FxComboBox extends Application {
    public static void main(String [] args) {
        launch(args);
    }
    @Override
    public void start(Stage primaryStage) {
        ObservableList<Product> products = FXCollections.observableArrayList(
                                                new Product(1, "Books"),
                                                new Product(2, "Pencils"),
                                                new Product(3, "Folders"),
                                                new Product(9, "Paper Clips"));
        products.add(0, null);
        ComboBox<Product> productsCombo = new ComboBox<>();
        productsCombo.setItems(products);
        HBox hbox = new HBox();
        hbox.setAlignment(Pos.CENTER);
        hbox.getChildren().add(productsCombo);
        Scene scene = new Scene(hbox, 400, 200);
        primaryStage.setTitle("Combo Box Demo");
        primaryStage.setScene(scene);
        primaryStage.show();
    }
}
class Product {
    private int id;
    private String name;
    public Product(int id, String name) {
        this.name = name;
        this.id = id;
    }
    public int getId() {
        return id;
    }
    public String getName() {
        return name;
    }
    @Override
    public String toString() {
        return Integer.toString(id) + " " + name;
    }
}


更新:

以下是解决方法: 创建一个名为{em> dummy 的Product。这将具有id = -1(或在实际应用中未使用的东西)和name =“”(空字符串)。 Product类的重写toString方法可能会考虑使用此 dummy 产品并返回一个空字符串:

public String toString() {
    if ((id == -1) && (name.isEmpty())) {
        return "";
    }
    else {
        return Integer.toString(id) + " " + name;
    }
}

示例代码反映了这一点:

更改此内容:

products.add(0, null);

至:

Product dummy = new Product(-1, "");
products.add(0, dummy);

答案 1 :(得分:0)

您可以创建一个ComboBoxItem<T>类,其中包含一个Producto类型的Element。 这样,您可以将所包含的元素设置为null,但仍可以在toString()方法中返回一个String。 然后,Combox将包含ComboxItems而不是Products。

答案 2 :(得分:0)

这是适用于您要使用的任何自定义对象的解决方案。

首先创建一个名为GenericCallback的类:

import javafx.scene.control.ListCell;
import javafx.scene.control.ListView;
import javafx.util.Callback;

public abstract class GenericCallback<T> implements Callback<ListView<Object>, ListCell<Object>> {
    @Override
    public ListCell<Object> call(ListView<Object> param) {
        final ListCell<Object> cell = new ListCell<Object>() {
            @Override
            protected void updateItem(Object t, boolean empty) {
                super.updateItem(t, empty);
                try {
                    if (t instanceof String) {
                        setText((String)t);
                    } else {
                        //hopefully it is generic
                        T abc = (T)t;
                        setText(toText(abc));
                    }
                } catch (Exception e) {
                    //oh well, looks like it was not.
                    setText("");
                }
        };
        return cell;
    }

    public abstract String toText(T object);
}

然后您可以像这样实现它:

GenericCallback gc = new GenericCallback<User>() {
    @Override
    public String toText(User user) {
        return FormattingUtil.getUserName(user);
    }
};
ComboBox comboboxUser = new Combobox();
comboboxUser.setButtonCell(gc.call(null));
comboboxUser.setCellFactory(gc);
comboboxUser.setOnAction(new EventHandler<ActionEvent>() {
   @Override
   public void handle(ActionEvent event) {
        Object selectedItem = comboboxIzd.getSelectionModel().getSelectedItem();
        if (selectedItem instanceof User) {
            User thisUserIsSelected = (User) selectedItem;
            //do whatever you wish with it
        } else {
            //empty item was selected - no user was selected, do whatever you wish with it
        }
    }
});

这是您可以用字符串或对象填充组合框的方法:

comboboxUser.getItems().add("");//add empty string for example
comboboxIzd.getItems().add("no selection but still some text");
comboboxUser.getItems().addAll(listOfSomeUserObjects);
comboboxIzd.getItems().add("no selection at the end ...");

没有运行时错误,因为您没有将空对象添加到组合框。使用新的组合框,您只需替换通用类型User,即可处理另一个对象。希望对您有所帮助。