【问题标题】:How can I to force JavaFX ComboBox dropdown list cells to be re-rendered?如何强制重新呈现 JavaFX ComboBox 下拉列表单元格?
【发布时间】:2016-07-05 21:46:54
【问题描述】:

我有一个 Java 8 可编辑 ComboBox,其中默认项为粗体,非默认项由 CellFactory 非粗体。 当默认值更改为另一个项目时,我发现让 CellFactory 将新默认值加粗和旧默认值不加粗的唯一方法是删除并重新添加旧的和新的默认项目。这需要相当多的代码来处理新项目变为当前项目,因为之前的当前项目已被删除,然后将当前项目设置为我们正在修改的项目。

有没有一种很好的方法可以将一个单元格标记为脏并需要重新渲染,这样我就不必删除并重新添加 2 个单元格?

我已经用谷歌搜索了半天,但也许我没有问对正确的问题。

我想如果我只是清除所有组合框项并重新添加它们,控制代码会更简单,但这不是很有效。

编辑:根据要求,这里是 CellFactory:

            bookComboBox.setCellFactory(
        new Callback<ListView<String>, ListCell<String>>() {
            @Override public ListCell<String> call(ListView<String> param) {
                final ListCell<String> cell = new ListCell<String>() {
                    {
                        super.setPrefWidth(100);
                    }
                    @Override public void updateItem(String item,
                        boolean empty) {
                            super.updateItem(item, empty);
                            if (item != null) {
                                setText(item);
                                if (item.equals(Book.getDefaultBook())) {
                                    setFont(Font.font("System", FontWeight.BOLD, 14));
                                    System.out.println("bookComboBox.setCellFactory: set BOLD item=" + item);
                                }
                                else {
                                    setFont(Font.font("System", FontWeight.NORMAL, 14));
                                    System.out.println("bookComboBox.setCellFactory: set NORMAL item=" + item);
                                }
                            }
                            else {
                                setText(null);
                            }
                        }
                    };
                    return cell;
                }
            });

我没有改变单元格的值,只是渲染时使用的字体。 我没有使用 onEditCommit()。 我使用 bookComboBox.setOnAction 侦听器对组合框选择更改做出反应。 当在组合框中输入文本并按下操作键 (ENTER) 或组合框失去焦点时,也会发生 setOnAction 事件。

【问题讨论】:

  • CellFactory是如何实现的?据推测,所需要的只是更新其中的控件......
  • 请显示一些代码,或者您使用onEditCommit?原则上,单元格应该自动重新渲染。
  • @jorn:单元格只会自动渲染一次。看来您必须更改单元格中的值或再次删除/添加它才能重新渲染它。所有这些选项都会导致发生不需要的 ComboBox.setOnAction 事件。
  • 我从docs.oracle.com/javase/8/javafx/api/javafx/scene/control/… 看到,仅呈现显示 VisibleRowCount 所需的单元格,因此如果滚动列表,则可能会重新呈现单元格,但这对我没有帮助.

标签: java javafx combobox


【解决方案1】:

通过使用ObservableValue&lt;Boolean&gt; 告诉您每个单元格的项目是否应为粗体,您可以创建更新字体的绑定。

例子:

这会将每个项目用作默认值 1 秒,然后再将下一个项目用作默认值。

@Override
public void start(Stage primaryStage) {
    ComboBox<String> comboBox = new ComboBox<>(FXCollections.observableArrayList(
            "item 1",
            "item 2",
            "item 3",
            "item 4",
            "item 5"
    ));

    final Font BOLD_FONT = Font.font("System", FontWeight.BOLD, 14);
    final Font NORMAL_FONT = Font.font("System", FontWeight.NORMAL, 14);

    final StringProperty defaultValue = new SimpleStringProperty();
    comboBox.setCellFactory(lv -> new ListCell<String>() {

        {
            // use bold font if the item property contains the
            // same value as the defaultValue property
            fontProperty().bind(Bindings.when(itemProperty().isEqualTo(defaultValue))
                                        .then(BOLD_FONT)
                                        .otherwise(NORMAL_FONT));
        }

        @Override
        protected void updateItem(String item, boolean empty) {
            super.updateItem(item, empty);

            if (empty || item == null) {
                setText(null);
            } else {
                setText(item);
            }
        }

    });

    // change default every second
    PauseTransition animation = new PauseTransition(Duration.seconds(1));
    EventHandler<ActionEvent> eventHandler = new EventHandler<ActionEvent>() {

        private Iterator<String> iterator = comboBox.getItems().iterator();

        @Override
        public void handle(ActionEvent event) {
            if (!iterator.hasNext()) {
                iterator = comboBox.getItems().iterator();
            }
            defaultValue.set(iterator.next());
            animation.play();
        }
    };

    animation.setOnFinished(eventHandler);

    eventHandler.handle(null);
    Scene scene = new Scene(comboBox);

    primaryStage.setScene(scene);
    primaryStage.show();
} 

【讨论】:

  • 您好 Fabian,非常感谢!上面的代码虽然没有编译。 2 个缺失符号问题:Bindings.with 和 Duration.seconds。我不需要 Duration.seconds 但如果你能修复它会很好,所以这是一个工作示例。
  • @ChrisGood:两者都是 javaFX API 的一部分。您需要导入javafx.beans.binding.Bindingsjavafx.util.Duration
  • 啊!我让 netbeans 添加导入,但它错误地选择了 javax.script.Bindings 和 java.time.Duration。活到老,学到老。现在可以使用 - 再次感谢!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-06-02
  • 1970-01-01
  • 1970-01-01
  • 2021-10-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多