简体   繁体   English

JavaFx:不带ActionEvent的comboBox.setValue

[英]JavaFx: comboBox.setValue without ActionEvent

I have combobox with page numbers (1,2,3,etc). 我有带有页码(1、2、3等)的组合框。 When user select the certain page (by mouse or by keyboard(as combobox editable)).I want to show and total pages. 当用户选择特定页面时(通过鼠标或键盘(组合框可编辑))。我要显示和总计页面。 That's why on combobox action I also do: 这就是为什么我在组合框操作中也会这样做的原因:

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

so the final code looks like 所以最终的代码看起来像

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

However this code fires one more ActionEvent and code cycles. 但是,此代码又触发了一个ActionEvent和代码周期。 So I see two possible ways: 因此,我看到了两种可能的方法:

  1. Handle some specific events (but which and how?) 处理一些特定事件(但是哪些以及如何处理)
  2. Find the way to change the value in combobox without firing one more event (again how?) 寻找在不触发另一个事件的情况下更改组合框值的方法(再次如何?)

Can anyone help me to solve this problem? 谁能帮我解决这个问题?

setValue(...) changes the value that is held by the combo box (ie it changes the data, or the state of the underlying model). setValue(...)更改组合框保留的值(即,它更改数据或基础模型的状态)。 It seems to me that what you really want here is just to change the way the data is displayed. 在我看来,您真正想要的只是改变数据的显示方式。 You change the display of the selected value by setting the button cell. 您可以通过设置按钮单元格来更改所选值的显示。

Here is an example in which the button cell keeps track of both the selected item and the number of pages: 这是一个示例,其中按钮单元格同时跟踪所选项目和页面数:

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);
    }
}

If your ComboBox is editable, then the button cell is by default a TextField , and the combo box's converter is used to convert the string value in the text field to the model value, and vice-versa. 如果您的ComboBox是可编辑的,则默认情况下,按钮单元格是TextField ,组合框的converter用于将文本字段中的字符串值转换为模型值,反之亦然。 So in this case you just need to install a converter that converts between the integer x and the string "x / total" . 因此,在这种情况下,您只需要安装一个在整数x和字符串"x / total"之间转换的转换器。

Note that by default this converter is also used to display the text in the cells in the drop down, so if you want these to appear just as the integer values, you need to install a cellFactory to explicitly create those cells. 请注意,默认情况下,此转换器还用于在下拉列表的单元格中显示文本,因此,如果希望这些文本显示为整数值,则需要安装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);
    }
}

try to use prompt text instead setting value. 尝试使用提示文本代替设置值。

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

but I don't know if it work once value is selected by user. 但是我不知道一旦用户选择了值就行不通。 Maybe you will have to setValue(null) just to see prompt text again. 也许您只需要设置setValue(null)即可再次看到提示文本。 But then you would have to keep somewhere last selected value. 但是,那么您将必须保留最后选择的值。

First remove all the listeners from the value property if any and add action event filter, eg by adding a method: 首先,从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);
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM