首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >将ComboBox设置为只读,而不禁用使用JavaFX的ComboBox

将ComboBox设置为只读,而不禁用使用JavaFX的ComboBox
EN

Stack Overflow用户
提问于 2022-09-07 04:55:49
回答 3查看 118关注 0票数 1

我不想禁用ComboBox,因为我希望用户能够选择ComboBox按钮并查看ComboBox项。如果用户尝试在ComboBox中选择项,则会弹出一个窗口,说明用户处于只读模式,而ComboBox仍应在ComboBox按钮单元格中保留原始项。

有办法这样做吗?

顺便说一下,我看到以前的一篇文章问了同样的问题。,但使用来自ControlsFX的CheckComboBox。但是,由于我使用的是来自JavaFX 8的普通JavaFX,所以该帖子中的解决方案不适用于标准ComboBox

下面是一个最小可复制代码示例:

代码语言:javascript
运行
复制
public class Main extends Application {
    Stage window;
    Scene scene;
    public static void main(String[] args) {
        launch(args);
    }

    @Override
    public void start(Stage primaryStage) {
        window = primaryStage;
        window.setTitle("Read Only ComboBox");

        ObservableList<String> strings = FXCollections.observableArrayList();
        for (int i = 0; i <= 10; i++)
            strings.add("Item " + i);

        // Create the ComboBox with the data
        ComboBox<String> comboBox = new ComboBox<>(strings);
        comboBox.getSelectionModel().select(3);

        // Set comboBox to read only

        HBox layout = new HBox(10);
        layout.setPadding(new Insets(20, 20, 20,20));
        layout.getChildren().addAll(comboBox);

        scene = new Scene(layout, 300, 250);
        window.setScene(scene);
        window.show();
    }
}

我试图让ComboBox看起来像当用户选择ComboBox按钮单元格时。,然后一旦他们选择了任何项目,就会弹出一个窗口,说明它们处于只读模式,而ComboBox仍然应该选择“条目3”。

编辑1:这里的是使用[医]阿布拉码的完整堆栈跟踪。我没有修改任何代码。

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

编辑2:sorifiend和as的代码都按预期工作,但不是在包含JavaFX的JDK 8上工作。我使用了ZuluJDK17w/ JavaFX,他们的两个代码都使用那个JDK。我仍然在寻找解决方案,因为我正在从事的项目是在桌面应用程序中使用Java8SE。

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2022-09-07 10:40:08

小心: UX是可怕的-我们不能欺骗我们的用户相信他们可以改变任何事情,并告诉他们,他们不能在他们尝试!

此外,我们不能(我知道它在某个地方的java文档中,但在需要时永远找不到它;)将侦听器中的属性状态更改为该属性:大多数情况下,我们可以不去做它,但是它可能会有令人讨厌的、难以调试的副作用。

所有这些都是(老板坚持要实现错误的UX :) --这里有一个替代方法,可以替代听者做错误的事情。基本思想是将组合体的值绑定到一个固定的值。这样做可以有效地将其与选择状态断开--用户可以使用键更改选择(如果弹出窗口关闭),或者在下拉列表中导航(如果弹出显示)而不更改值。

下面是一个例子

  • 具有保存固定值的属性。
  • 具有切换readOnly状态的属性。
  • un/根据切换状态将组合体的值从/绑定到固定值
  • 同步是对un/bind和显示弹出窗口的选择
  • 注意:当绑定时,选择状态的侦听器仍将收到来自用户交互的通知(此时用户交互与组合体的值不同步)-应用程序代码必须知道这一事实。

守则:

代码语言:javascript
运行
复制
public class ReadonlyComboSelection extends Application {
    StringProperty fixedValue;
    BooleanProperty readonly;
    @Override
    public void start(Stage primaryStage) {
        primaryStage.setTitle("Read Only ComboBox");

        ObservableList<String> strings = FXCollections.observableArrayList();
        for (int i = 0; i <= 10; i++)
            strings.add("Item " + i);

        // Create the ComboBox with the data
        ComboBox<String> comboBox = new ComboBox<>(strings);
        // initialize the fixed selection
        fixedValue = new SimpleStringProperty(strings.get(3));
        readonly = new SimpleBooleanProperty() {

            @Override
            protected void invalidated() {
                if (get()) {
                    comboBox.valueProperty().bind(fixedValue);
                } else {
                    comboBox.valueProperty().unbind();
                }
                comboBox.getSelectionModel().select(comboBox.getValue());
            }

        };
        readonly.set(true);

        // make sure the selection in the popup is showing the value
        comboBox.setOnShowing(e -> {
            if (comboBox.valueProperty().isBound()) {
                comboBox.getSelectionModel().select(comboBox.getValue());
                if (comboBox.getSkin() instanceof ComboBoxListViewSkin skin) {
                    ListView<String> list = (ListView<String>) skin.getPopupContent();
                    list.getSelectionModel().select(comboBox.getValue());
                }
            }
        });

        // just for fun: dynamically change the readonly state
        CheckBox check = new CheckBox("selection is readonly");
        check.selectedProperty().bindBidirectional(readonly);

        HBox layout = new HBox(10, comboBox, check);

        Scene scene = new Scene(layout, 300, 250);
        primaryStage.setScene(scene);
        primaryStage.show();
    }

    public static void main(String[] args) {
        launch(args);
    }
}
票数 3
EN

Stack Overflow用户

发布于 2022-09-07 05:26:44

下面是一个粗略的解决方案,它将捕获事件并将其还原为默认的选择,我们可以做任何我们想做的事情,比如显示消息。如果应用程序没有处于只读模式,那么我们可以正常地处理该操作:

代码语言:javascript
运行
复制
//Value to track read only mode
Boolean readOnlyMode = true;

//Values to help revert the selection
int defaultSelection = 3;
//We use a flag so that the message is not displayed twice when we reset the selection
//You can remove then need for this by checking the item that was selected instead and only show the message if it was not te default item
boolean flagToggle = false;

//Add an event to revert the selection and show a message
comboBox.setOnAction((ActionEvent t) ->
{
    if(readOnlyMode){
        //Code here to show a message and revert the selection
        if(!flagToggle){
            //Replace this line with your pop up dialogue, etc
            System.out.println("The application is in Read Only mode");
            //flip the flag for displaying the message
            flagToggle = true;
        }
        //restore the flag
        else{
            flagToggle = false;
        }

        //reset the selection to default, if the selection is already back to the default then this will not trigger another selection event
        comboBox.getSelectionModel().select(defaultSelection);
    }
    else{
        System.out.println("The application is in Edit mode. Item "+ comboBox.getValue() + " selected.");
        //perform normal actions
        //call some method here?
    }
});
票数 2
EN

Stack Overflow用户

发布于 2022-09-07 05:52:35

ChangeListener添加到ComboBox的选择模型中。每当选择发生更改时,下面的代码将恢复原始选择并显示一条消息。注意,我任意地将初始ComboBox选择设置为其值列表中的第一项。

代码语言:javascript
运行
复制
import javafx.application.Application;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.Alert;
import javafx.scene.control.Alert.AlertType;
import javafx.scene.control.ButtonType;
import javafx.scene.control.ComboBox;
import javafx.scene.control.SingleSelectionModel;
import javafx.stage.Stage;

public class ApplicationMain extends Application {

    @Override
    public void start(Stage stage) throws Exception {
        ComboBox<String> combo = new ComboBox<>(FXCollections.observableArrayList("First",
                                                                                  "Second",
                                                                                  "Third",
                                                                                  "Fourth",
                                                                                  "Last"));
        SingleSelectionModel<String> selectionModel = combo.getSelectionModel();
        selectionModel.select(0);
        selectionModel.selectedItemProperty().addListener(new ChangeListener<String>() {
            boolean flag = true;
            @Override
            public void changed(ObservableValue<? extends String> observable, String oldValue, String newValue) {
                if (flag) {
                    flag = false;
                    selectionModel.select(oldValue);
                    flag = true;
                    Alert alert = new Alert(AlertType.WARNING, "Read only mode.", ButtonType.CLOSE);
                    alert.setHeaderText(null);
                    alert.showAndWait();
                }
            }
        });
        Group root = new Group(combo);
        Scene scene = new Scene(root, 250.0D, 60.0D);
        stage.setTitle("Example");
        stage.setScene(scene);
        stage.show();
    }

    public static void main(String[] args) {
        launch(args);
    }
}
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/73630307

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档