我想将CheckMenuItem
' s selectedProperty
绑定到另一个可观察值,例如cmi.selectedProperty().bind(myObs)
。但是,这是不可能的,因为框架在单击检查菜单项时设置selection属性(请参阅ContextMenuContent.java的line 1394)。
有没有办法拦截点击 - 这样我可以自己进行自定义处理 - 并仍然将选择属性绑定到另一个可观察对象?
我想我将点击视为更新某个州的请求。用户单击菜单项,然后程序尝试相应地更改某个状态,如果状态成功更新,则选择会更改。在' normal'条件,检查应在每次点击时切换;但是,如果发生了不好的事情,我更倾向于检查不会切换,而是反映程序的真实状态。
答案 0 :(得分:1)
执行此操作的一种方法(无需编写菜单项的外观)是使用图形滚动自己的菜单项。您可以只使用图形区域并从标准的模式样式表中窃取CSS。然后将图形的visible属性绑定到observable值,并在菜单项的action处理程序中切换observable值:
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);
}
}
和
签menu.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);
}
});