javafx2 tableview问题:单元格中的回调和可编辑组合框

时间:2014-11-12 16:17:09

标签: combobox callback javafx tableview

我遇到了tableview及其单元格的问题。我想用可编辑的组合框自定义单元格。这是我的组合框代码:

public class CbbxEditSuppr extends ComboBox<BoxItem> {

private TextField editor = null;
private ObservableList<BoxItem> items = null;

private double prefWidth = 0.0;


/**
 * Constructeur.
 * 
 * @param addedItems ObservableList<String>
 * @param prefWidth double largeur préférée
 */
public CbbxEditSuppr(ObservableList<String> addedItems, final double prefWidth) {
    // initialisation des attributs
    editor = this.getEditor();
    items = this.getItems();
    this.prefWidth = prefWidth;
    this.setPrefWidth(prefWidth);
    // initialisation du contenu de la cellule
    this.setCellFactory(new Callback<ListView<BoxItem>, ListCell<BoxItem>>() {
        @Override
        public ListCell<BoxItem> call(ListView<BoxItem> p) {
            final ListCell<BoxItem> cell = new ListCell<BoxItem>() {
                @Override
                protected void updateItem(BoxItem t, boolean bln) {
                    super.updateItem(t, bln);
                    if (t != null) {
                        setGraphic(t);
                    } else {
                        setGraphic(null);
                    }
                }
            };
            return cell;
        }
    });
    // déininition du converter
    this.setConverter(new StringConverter<BoxItem>() {
        @Override
        public String toString(BoxItem cbbx) {
            if (cbbx == null) {
                return null;
            } else {
                return cbbx.getName();
            }
        }


        @Override
        public BoxItem fromString(String id) {
            if (id != null) {
                final BoxItem box = new BoxItem(id, items, prefWidth);
                return box;
            } else {
                return null;
            }

        }
    });
    /* ajout des valeurs a la liste d'items */
    if (addedItems != null && addedItems.size() > 0) {
        for (String stg : addedItems) {
            if (stg != null) {
                final BoxItem hbox = new BoxItem(stg, items, this.prefWidth);
                items.add(hbox);
            }
        }
    }
    // permet de prendre en compte la touche ENTER, et ajouter des valeurs a la liste
    this.addEventFilter(KeyEvent.KEY_PRESSED, new EventHandler<KeyEvent>() {
        public void handle(final KeyEvent event) {
            if (event != null && event.getCode().equals(KeyCode.ENTER)) {
                if (editor.getText().trim().length() > 0) {
                    addItem(editor.getText(), prefWidth);
                    editor.clear();
                }
            }
        }
    });
    // propriétés editable et selection du premier element
    this.setEditable(true);
    this.getSelectionModel().selectFirst();
    // ajout de l'affichage du menu popup lors du focus du textfield d'edition de la combobox
    editor.focusedProperty().addListener(new ChangeListener<Boolean>() {
        @Override
        public void changed(ObservableValue<? extends Boolean> arg0, Boolean arg1, Boolean arg2) {
            if (arg0 != null && arg2) {
                showpopupMenu();
            }
        }
    });
}


/**
 * Permet l'affichage du menu popup dans une cellule.
 */
private void showpopupMenu() {
    if (!isShowing() && this != null) {
        this.show();
    }
}


/**
 * Ajoute un item à la liste
 * 
 * @param stg String nom de l'item
 * @param width double taille préférée
 */
public void addItem(String stg, double width) {
    if (stg != null) {
        items.add(new BoxItem(stg, items, width));
    }
}


/**
 * Retourne la description du contenu de la liste
 */
public String toString() {
    final StringBuilder stgBuilder = new StringBuilder("[ ");
    if (items != null && items.size() > 0) {
        final BoxItem lastItem = items.get(items.size() - 1);
        for (BoxItem item : items) {
            if (item != null) {
                stgBuilder.append(item.getName());
                if (!item.equals(lastItem)) {
                    stgBuilder.append(", ");
                }
            }
        }
    }
    stgBuilder.append(" ]");
    return stgBuilder.toString();

}

public class BoxItem extends HBox {

private Label lbl = null;
private Button btn = null;
private ObservableList<BoxItem> listItems;


/**
 * Constructeur.
 * 
 * @param stg String nom de la box
 * @param items ObservableList<BoxItem> liste d'items de la combobox
 * @param prefWidth int largeur de la combobox
 */
public BoxItem(String stg, final ObservableList<BoxItem> items, double prefWidth) {
    super();
    this.listItems = items;
    if (stg != null) {
        this.setSpacing(40);
        lbl = new Label(stg);
        lbl.setPrefWidth(prefWidth);
        btn = new Button("x");
        this.getChildren().addAll(lbl, btn);

        btn.setOnMousePressed(new EventHandler<Event>() {
            @Override
            public void handle(Event arg0) {
                final BoxItem bx = (BoxItem) btn.getParent();
                if (bx != null) {
                    listItems.remove(bx);
                }
             }
  });
     }
 }


 /**
 * Retourne le texte inscrit dans le label
 * 
 * @return String
 */
public String getName() {
    if (lbl != null) {
        return lbl.getText();
    }
    return null;
}


/**
 * retourne le bouton contenu dans une box
 * 
 * @return Button
 */
public Button getBtn() {
    return btn;
}
}
}

然后我用这个callbak启动我的colum:

 Callback<TableColumn<DonorData, ObservableList<BoxItem>>, TableCell<DonorData,   ObservableList<BoxItem>>> cellFactoryEditingCell = new Callback<TableColumn<DonorData, ObservableList<BoxItem>>, TableCell<DonorData, ObservableList<BoxItem>>>() {
        public TableCell<DonorData, ObservableList<BoxItem>> call(TableColumn<DonorData, ObservableList<BoxItem>> data) {
            return new CbbxEditingCell<DonorData, ObservableList<BoxItem>>();
        }
    };

    colDonorOtherRef.setCellValueFactory(new PropertyValueFactory<DonorData, ObservableList<BoxItem>>("othersRef"));
    colDonorOtherRef.setCellFactory(cellFactoryEditingCell);
    colDonorOtherRef.setOnEditCommit(new EventHandler<CellEditEvent<DonorData, ObservableList<BoxItem>>>() {
        @Override
        public void handle(CellEditEvent<DonorData, ObservableList<BoxItem>> event) {
            final DonorData rec = event.getTableView().getItems().get(event.getTablePosition().getRow());
            //TODO action
}
    });

with:CbbxEditingCell.java

public class CbbxEditingCell<S, T> extends TableCell<S, T> {
private CbbxEditSuppr cbbx;
private ObservableList<String> listValues = null;

private boolean isSelectFirst = false;


public CbbxEditingCell() {
    listValues = FXCollections.observableArrayList(new ArrayList());
}


@Override
public void startEdit() {
    if (!isEmpty()) {
        super.startEdit();
        createTextField();
        setText(null);
        setGraphic(cbbx);
    }
}


@Override
public void cancelEdit() {
    super.cancelEdit();
    try {
        if (!getItem().toString().equals("null")) {
            setText(cbbx.toString());
        }
    } catch (Exception e) {
    }
    setGraphic(null);
}


@Override
public void updateItem(T item, boolean empty) {
    super.updateItem(item, empty);
    if (empty) {
        setText(null);
        setGraphic(null);
    } else {
        if (isEditing()) {
            setText(null);
            setGraphic(cbbx);
        } else {
            if (getItem() != null && cbbx != null) {
                setText(cbbx.toString());
            } else {
                setText(null);
            }
            setGraphic(null);
        }
    }
}


private void createTextField() {
    final double width = this.getWidth() - this.getGraphicTextGap() * 2;
    cbbx = new CbbxEditSuppr((ObservableList<String>) listValues, width);
    if (isSelectFirst) {
        cbbx.getSelectionModel().selectFirst();
    }
    cbbx.setMinWidth(width);
    cbbx.setOnKeyReleased(new EventHandler<KeyEvent>() {
        @Override
        public void handle(KeyEvent t) {
            if (t.getCode() == KeyCode.ENTER) {
                commitEdit((T) cbbx.getItems());
            } else if (t.getCode() == KeyCode.ESCAPE) {
                cancelEdit();
            }
        }
    });
    cbbx.focusedProperty().addListener(new ChangeListener<Boolean>() {
        @Override
        public void changed(ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean newValue) {
            if (!newValue) {
                commitEdit((T) cbbx.getItems());
            }

        }
    });

}


public void selectFirstItem() {
    isSelectFirst = true;
}

}

我的问题:当我点击一个单元格时,我总是一个空的组合框。我不知道如何修改我的回调以获得该单元格中的行或数据的引用。

你有什么想法吗? 感谢

1 个答案:

答案 0 :(得分:0)

我认为问题出现是因为BoxItemNode子类 - 即您正在混合视图类型和数据类型。 (BoxItem t;方法中有setGraphic(t);updateItem()。)ComboBox特别糟糕,因为所选项最终会尝试在场景图中出现两次(一次在ComboBox下拉,一次在&#34;按钮单元格&#34;显示所选内容。

参见&#34;关于将节点插入ComboBox项目列表的警告&#34;在ComboBox Javadocs

相反,使用不同的类来表示您正在显示的数据以及用于显示它们的UI控件。