【问题标题】:JavaFx: comboBox.setValue without ActionEventJavaFx:没有 ActionEvent 的 comboBox.setValue
【发布时间】:2017-12-11 04:54:05
【问题描述】:

我有带有页码(1、2、3 等)的组合框。当用户选择某个页面时(通过鼠标或键盘(作为可编辑的组合框))。我想显示和总页数。这就是为什么在组合框操作上我也会这样做:

combobox.setValue(currentPage+"/"+totalPages)

所以最终的代码看起来像

   @FXML
    private void onPageComboBoxAction(ActionEvent event){
       ....
       combobox.setValue(currentPage+"/"+totalPages)
    }

但是,此代码会再触发一个 ActionEvent 和代码周期。所以我看到了两种可能的方法:

  1. 处理一些特定事件(但哪些以及如何处理?)
  2. 想办法改变组合框中的值而无需再触发一个事件(再次如何?)

谁能帮我解决这个问题?

【问题讨论】:

  • 请将代码添加到您的问题中。
  • @Tomek 我编辑了帖子。
  • 你试过我的解决方案了吗?
  • @Tomek 你的解决方案不是我要找的。因为promttext 是promtext,价值就是价值。您的解决方案将它们混合在一起。我的意思是你的解决方案可以工作。但是使用它我们可以忘记promttext的优势。
  • 你能澄清一下你的意思吗? IE。总页数是可变的,还是固定的?您真的只是希望所选值的显示与下拉列表中的显示不同吗? ComboBox 是可编辑的,还是只允许用户从下拉列表中选择?

标签: java javafx


【解决方案1】:

setValue(...) 更改组合框保存的值(即,它更改数据或基础模型的状态)。在我看来,你真正想要的只是改变数据的显示方式。您可以通过设置按钮单元来更改所选值的显示。

这是一个示例,其中按钮单元同时跟踪所选项目和页数:

import java.util.Random;
import java.util.stream.IntStream;

import javafx.application.Application;
import javafx.collections.ListChangeListener.Change;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.ComboBox;
import javafx.scene.control.ListCell;
import javafx.scene.layout.HBox;
import javafx.stage.Stage;

public class PageNumberCombo extends Application {

    private static final Random RNG = new Random();

    @Override
    public void start(Stage primaryStage) {
        ComboBox<Integer> combo = new ComboBox<>();
        combo.setButtonCell(new ListCell<Integer>() {
            {
                itemProperty().addListener((obs, oldValue, newValue) -> update());
                emptyProperty().addListener((obs, oldValue, newValue) -> update());
                combo.getItems().addListener((Change<? extends Integer> c) -> update());
            }

            private void update() {
                if (isEmpty() || getItem() == null) {
                    setText(null);
                } else {
                    setText(String.format("%d / %d", getItem().intValue(), combo.getItems().size()));
                }
            }
        });

        Button reloadButton = new Button("Reload");
        reloadButton.setOnAction(e -> reload(combo));

        reload(combo);

        HBox root = new HBox(10, combo, reloadButton);
        root.setAlignment(Pos.CENTER);
        root.setPadding(new Insets(24));
        primaryStage.setScene(new Scene(root, 240, 60));
        primaryStage.show();
    }

    private void reload(ComboBox<Integer> combo) {
        int numPages = RNG.nextInt(10) + 11 ;
        combo.getItems().clear();
        IntStream.rangeClosed(1, numPages).forEach(combo.getItems()::add);
    }

    public static void main(String[] args) {
        launch(args);
    }
}

如果你的ComboBox是可编辑的,那么按钮单元格默认为TextField,组合框的converter用于将文本字段中的字符串值转换为模型值,反之亦然.所以在这种情况下,您只需要安装一个转换器,它可以在整数x 和字符串"x / total" 之间进行转换。

请注意,默认情况下,此转换器还用于显示下拉单元格中的文本,因此如果您希望这些显示为整数值,则需要安装 cellFactory 以显式创建这些单元格.

import java.util.Random;
import java.util.stream.IntStream;

import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.ComboBox;
import javafx.scene.control.ListCell;
import javafx.scene.layout.HBox;
import javafx.stage.Stage;
import javafx.util.StringConverter;

public class PageNumberCombo extends Application {

    private static final Random RNG = new Random();

    @Override
    public void start(Stage primaryStage) {
        ComboBox<Integer> combo = new ComboBox<>();

        combo.setEditable(true);
        combo.setConverter(new StringConverter<Integer>() {

            @Override
            public String toString(Integer object) {
                return object + " / " + combo.getItems().size();
            }

            @Override
            public Integer fromString(String string) {
                int index = string.indexOf('/');
                if (index < 0) {
                     index = string.length();
                }
                String text = string.substring(0, index).trim();
                try {
                    return Integer.parseInt(text);
                } catch (Exception exc) {
                    return 0 ;
                }
            }

        });

        combo.setCellFactory(lv -> new ListCell<Integer>() {
            @Override
            public void updateItem(Integer item, boolean empty) {
                super.updateItem(item, empty);
                if (empty) {
                    setText(null) ;
                } else {
                    setText(item.toString());
                }
            }
        });

        Button reloadButton = new Button("Reload");
        reloadButton.setOnAction(e -> reload(combo));

        reload(combo);

        HBox root = new HBox(10, combo, reloadButton);
        root.setAlignment(Pos.CENTER);
        root.setPadding(new Insets(24));
        primaryStage.setScene(new Scene(root, 240, 60));
        primaryStage.show();
    }

    private void reload(ComboBox<Integer> combo) {
        int numPages = RNG.nextInt(10) + 11 ;
        combo.getItems().clear();
        IntStream.rangeClosed(1, numPages).forEach(combo.getItems()::add);
    }

    public static void main(String[] args) {
        launch(args);
    }
}

【讨论】:

  • 嘘!我以为我对您的代码感到疯狂:)。是的,这就是我需要的。但是,如果组合框是可编辑的,您的代码将不起作用。能解决吗?
  • 呃,是的,你确实说过它是可编辑的。我错过了。我认为您可以使用 StringConverter 来完成此操作,但我必须弄清楚.. 稍后我会看看是否有时间编辑。
  • 我试过 StringConverter,但据我所知,它不仅用于 buttonCell。
  • 那么,不可能吗?
  • 不,按照我的建议使用StringConverter。如果您希望下拉列表中的单元格不同,只需使用通常的cellFactory。查看更新。
【解决方案2】:

首先从 value 属性中删除所有侦听器(如果有)并添加操作事件过滤器,例如通过添加方法:

public class MyComboBox extends ComboBox<String> {
    public void setValueSilently(String value) {
        EventHandler<ActionEvent> filter = e -> e.consume();
        valueProperty().removeListener(myValueListener); // a custom listener
        addEventFilter(ActionEvent.ACTION, filter);
        setValue(value);
        removeEventFilter(ActionEvent.ACTION, filter);
        valueProperty().addListener(myValueListener);
    }
}

【讨论】:

    【解决方案3】:

    尝试使用prompt text 代替设置值。

    combobox.setPromptText(currentPage+"/"+totalPages);
    

    但我不知道一旦用户选择了值,它是否会起作用。也许您必须setValue(null) 才能再次看到提示文本。但是你必须保留最后选择的值。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-04-02
      • 1970-01-01
      • 2016-06-11
      • 1970-01-01
      • 2023-03-31
      • 2016-10-20
      相关资源
      最近更新 更多