【问题标题】:How do I bind CheckMenuItem.selectedProperty() to another ObservableValue?如何将 CheckMenuItem.selectedProperty() 绑定到另一个 ObservableValue?
【发布时间】:2017-05-23 15:31:23
【问题描述】:

我想将CheckMenuItemselectedProperty 绑定到另一个可观察值,例如cmi.selectedProperty().bind(myObs)。但是,这是不可能的,因为框架会在单击检查菜单项时设置 selection 属性(参见 ContextMenuContent.java 的 line 1394)。

有没有办法拦截点击——以便我可以进行自己的自定义处理——并且仍然将 selection 属性绑定到另一个 observable?

我想我将点击视为更新某些状态的请求。用户单击菜单项,然后程序会尝试相应地更改某些状态,如果状态成功更新,则选择会更改。在“正常”条件下,检查应在每次点击时切换;但是,如果发生不好的事情,我希望检查不切换,而是反映程序的真实状态。

【问题讨论】:

  • "Binding" 表示选中的属性总是等于要绑定的属性的值,这与允许用户更改值。所以目前还不清楚你想在这里做什么。可能您应该绑定选定的属性并禁用检查菜单项,或者您应该在可观察值上使用侦听器而不是绑定。 (或者你可能完全有错误的方法......?)
  • 我又加了一段;希望这能更好地解释我正在尝试做的事情。

标签: java javafx binding menuitem


【解决方案1】:

一种方法(无需为菜单项编写外观)是使用图形滚动您自己的菜单项。您可以只使用图形区域并从标准 modena 样式表中窃取 CSS。然后将图形的可见属性绑定到可观察值,并在菜单项的操作处理程序中切换可观察值:

import java.util.Random;

import javafx.application.Application;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.scene.Scene;
import javafx.scene.control.Alert;
import javafx.scene.control.Alert.AlertType;
import javafx.scene.control.ButtonType;
import javafx.scene.control.Menu;
import javafx.scene.control.MenuBar;
import javafx.scene.control.MenuItem;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.Region;
import javafx.stage.Stage;

public class VetoableMenuItemWithCheck extends Application {

    @Override
    public void start(Stage primaryStage) {
        BorderPane root = new BorderPane();
        MenuBar menuBar = new MenuBar() ;
        Menu choices = new Menu("Choices");

        // observable boolean value to which we're going to bind:
        BooleanProperty selected = new SimpleBooleanProperty();

        // graphic for displaying checkmark
        Region checkmark = new Region();
        checkmark.getStyleClass().add("check-mark");

        // bind visibility of graphic to observable value:
        checkmark.visibleProperty().bind(selected);

        MenuItem option = new MenuItem("Option", checkmark);

        choices.getItems().add(option);

        Random rng = new Random();

        // when menu item action occurs, randomly fail (with error alert),
        // or update boolean property (which will result in toggling check mark):
        option.setOnAction(e -> {
            if (rng.nextDouble() < 0.25) {
                Alert alert = new Alert(AlertType.ERROR, "I'm sorry Dave, I'm afraid I can't do that", ButtonType.OK);
                alert.showAndWait();
            } else {
                selected.set(! selected.get());
            }
        });

        menuBar.getMenus().add(choices);
        root.setTop(menuBar);

        Scene scene = new Scene(root, 400, 400);
        scene.getStylesheets().add("check-menu.css");
        primaryStage.setScene(scene);
        primaryStage.show();
    }

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

检查菜单.css:

.check-mark {
    -fx-background-color: -fx-mark-color;
    -fx-shape: "M0,5H2L4,8L8,0H10L5,10H3Z";
    -fx-scale-shape: false;
    -fx-padding: 0em 0.11777em 0em 0em;
}

可能有更简单的方法,但这似乎还不错。

可否决单选菜单项的版本可以遵循相同的基本理念,但具有

ObjectProperty<MenuItem> selectedItem = new SimpleObjectProperty<>();

然后为每个菜单项做

checkmark.visibleProperty().bind(selectedItem.isEqualTo(option));

option.setOnAction(e -> {
    if (successful()) {
        selectedItem.set(option);
    }
});

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-11-08
    • 1970-01-01
    • 2017-05-11
    • 1970-01-01
    • 2015-02-21
    • 1970-01-01
    • 1970-01-01
    • 2020-02-20
    相关资源
    最近更新 更多