正常的SplitMenuButton如下所示: Standard SplitMenuButton
我想在JavaFX SplitMenuButton中更改箭头的位置,但是如果有一个配置会给我这样的东西,就无法解决: SplitMenuButton with arrow on bottom
这是可能的还是我需要创建一个定制版本的分割菜单按钮?
答案 0 :(得分:0)
使用JavaFX SplitMenuButton之后,我找不到任何方法可以轻松地重现我需要的东西(默认右边的菜单箭头)。我创建了一个按钮类,允许箭头按钮放在主按钮的任何一侧(甚至隐藏)。这个课程没有得到完善,但能胜任。这个示例类的优点是箭头侧可以动态更改。
课程代码:
public class MyButton extends Group {
private ButtonBase label;
private ButtonBase arrowButton;
protected ContextMenu popup;
private ObjectProperty<SplitMode> splitMode;
private DoubleProperty sizeBinding;
private DoubleProperty layoutBinding;
private double oldSizeValue;
private double oldLayoutValue;
private PseudoClass layoutClass;
//
private static PseudoClass TOP_PSEUDO_CLASS = PseudoClass.getPseudoClass("top");
private static PseudoClass BOTTOM_PSEUDO_CLASS = PseudoClass.getPseudoClass("bottom");
private static PseudoClass LEFT_PSEUDO_CLASS = PseudoClass.getPseudoClass("left");
private static PseudoClass RIGHT_PSEUDO_CLASS = PseudoClass.getPseudoClass("right");
private static PseudoClass HIDDEN_PSEUDO_CLASS = PseudoClass.getPseudoClass("hidden");
public static enum SplitMode {
SPLIT_TOP, // put arrow buton on top
SPLIT_RIGHT, // put arrow button on right
SPLIT_BOTTOM, // bottom
SPLIT_LEFT, // left
HIDDEN // hides the arrow button regardless of visibility
}
private void changeToPseudoClass(PseudoClass newClass) {
pseudoClassStateChanged(layoutClass, false);
pseudoClassStateChanged(newClass, true);
layoutClass = newClass;
}
private void bindHidden() {
if (sizeBinding != null) {
sizeBinding.unbind();
sizeBinding.set(oldSizeValue);
}
if (layoutBinding != null) {
layoutBinding.unbind();
layoutBinding.set(oldLayoutValue);
}
arrowButton.setVisible(false);
changeToPseudoClass(HIDDEN_PSEUDO_CLASS);
}
private void bindSizeAndLayout(DoubleProperty sizeFrom, ReadOnlyDoubleProperty sizeTo,
DoubleProperty layoutFrom, ReadOnlyDoubleProperty layoutTo,
PseudoClass newPseudoClass) {
if (sizeBinding != null) {
sizeBinding.unbind();
sizeBinding.set(oldSizeValue);
}
if (layoutBinding != null) {
layoutBinding.unbind();
layoutBinding.set(oldLayoutValue);
}
oldSizeValue = sizeFrom.get();
sizeBinding = sizeFrom;
oldLayoutValue = layoutFrom.get();
layoutBinding = layoutFrom;
sizeFrom.bind(sizeTo);
layoutFrom.bind(layoutTo);
changeToPseudoClass(newPseudoClass);
arrowButton.setVisible(true);
}
public void setSplitMode(SplitMode mode) {
if (splitMode == null) {
splitMode = new SimpleObjectProperty();
}
if (splitMode.get() == mode) {
return;
} // no changes needed
splitMode.set(mode);
// set up new bindings
switch (mode) {
case SPLIT_BOTTOM:
// bind arrowbutton width to label width
// bind arrowbutton starting position to bottom of label
bindSizeAndLayout(arrowButton.prefWidthProperty(), label.widthProperty(),
arrowButton.layoutYProperty(), label.heightProperty(),
BOTTOM_PSEUDO_CLASS);
break;
case SPLIT_RIGHT:
// bind arrowbutton height to label height
bindSizeAndLayout(arrowButton.prefHeightProperty(), label.heightProperty(),
arrowButton.layoutXProperty(), label.widthProperty(),
RIGHT_PSEUDO_CLASS);
break;
case SPLIT_LEFT:
// bind arrowbutton height to label height
bindSizeAndLayout(arrowButton.prefHeightProperty(), label.heightProperty(),
label.layoutXProperty(), arrowButton.widthProperty(),
LEFT_PSEUDO_CLASS);
break;
case SPLIT_TOP:
// bind arrowbutton width to label height
bindSizeAndLayout(arrowButton.prefWidthProperty(), label.widthProperty(),
label.layoutYProperty(), arrowButton.heightProperty(),
TOP_PSEUDO_CLASS);
break;
case HIDDEN:
// unbind all and hide button
bindHidden();
break;
}
}
public SplitMode getSplitMode() {
return (splitMode == null) ? SplitMode.HIDDEN : splitMode.get();
}
public ObjectProperty splitModeProperty() {
return splitMode;
}
public ButtonBase getButton() {
return label;
}
public ButtonBase getArrowButton() {
return arrowButton;
}
// Test suite
public MyButton() {
this("");
}
public MyButton(String text) {
this(text, SplitMode.SPLIT_RIGHT);
}
@SuppressWarnings("OverridableMethodCallInConstructor")
public MyButton(String text, SplitMode mode) {
label = new Button(text);
label.getStyleClass().setAll("label");
arrowButton = new Button();
// bind the managed property to visibility.
// we dont want to manage an invisible button.
arrowButton.managedProperty().bind(arrowButton.visibleProperty());
arrowButton.getStyleClass().setAll("arrow-button");
getStyleClass().setAll("split-menu-button");
getChildren().clear();
getChildren().addAll(label, arrowButton);
setSplitMode(mode);
}
}// end of class
MyButton类创建其他伪类,以便为每一方启用特殊格式。
示例css:
.split-menu-button > .label {
-fx-background-color: -fx-outer-border, -fx-inner-border, -fx-body-color;
-fx-background-insets: 0, 1 0 1 1, 2 1 2 2;
-fx-background-radius: 5 0 0 5, 4 0 0 4, 3 0 0 3;
-fx-padding: 0.166667em 0.667em 0.25em 0.833333em; /* 2 8 3 10 */
/* -fx-graphic:url("./icon_32.png"); */
-fx-content-display: top;
-fx-alignment: center;
}
.split-menu-button:top > .label {
-fx-background-insets: 0, 1 0 1 1, 2 1 2 2;
-fx-background-radius: 0 0 5 5, 0 0 4 4, 0 0 3 3;
}
.split-menu-button:right > .label {
-fx-background-insets: 0, 1 0 1 1, 2 1 2 2;
-fx-background-radius: 5 0 0 5, 4 0 0 4, 3 0 0 3;
}
.split-menu-button:bottom > .label {
-fx-background-insets: 0, 1 0 1 1, 2 1 2 2;
-fx-background-radius: 5 5 0 0, 4 4 0 0, 3 3 0 0;
}
.split-menu-button:left > .label {
-fx-background-insets: 0, 1 0 1 1, 2 1 2 2;
-fx-background-radius: 0 5 5 0, 0 4 4 0, 0 3 3 0;
}
.split-menu-button:hidden > .label {
-fx-background-insets: 0, 1 0 1 1, 2 1 2 2;
-fx-background-radius: 5 5 5 5, 4 4 4 4, 3 3 3 3;
}
.split-menu-button > .arrow-button {
-fx-background-color: -fx-outer-border, -fx-inner-border, -fx-body-color;
-fx-background-insets: 0, 1, 2;
-fx-background-radius: 0 5 5 0, 0 4 4 0, 0 3 3 0;
-fx-padding: 0; /* 0.5em 0.667em 0.5em 0.667em; /* 6 8 6 8 */
-fx-graphic:url("./arrow.png");
-fx-alignment:center;
}
.split-menu-button:top > .arrow-button {
-fx-background-insets: 0, 1, 2;
-fx-background-radius: 5 5 0 0, 4 4 0 0, 3 3 0 0;
}
.split-menu-button:right > .arrow-button {
-fx-background-insets: 0, 1, 2;
-fx-background-radius: 0 5 5 0, 0 4 4 0, 0 3 3 0;
}
.split-menu-button:bottom > .arrow-button {
-fx-background-insets: 0, 1, 2;
-fx-background-radius: 0 0 5 5, 0 0 4 4, 0 0 3 3;
}
.split-menu-button:left > .arrow-button {
-fx-background-insets: 0, 1, 2;
-fx-background-radius: 5 0 0 5, 4 0 0 4, 3 0 0 3;
}
&#13;
示例应用程序以测试按钮。
import javafx.application.Application;
import static javafx.application.Application.launch;
import javafx.event.ActionEvent;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.ContextMenu;
import javafx.scene.control.Label;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
import MyButton.SplitMode;
public class SimpleTest
extends Application {
Stage primaryStage;
protected ContextMenu popup;
@Override
public void start(final Stage stage) throws Exception {
primaryStage = stage;
primaryStage.setTitle("SimpleTest.");
Label label = new Label();
Button rotate = new Button("Rotate");
MyButton b = new MyButton("My Test", SplitMode.SPLIT_TOP);
label.setText(b.getSplitMode().toString());
StackPane sp = new StackPane();
sp.setPrefSize(200, 200);
sp.getStylesheets().add("test.css");
rotate.setOnAction((ActionEvent t) -> {
switch(b.getSplitMode()){
case SPLIT_TOP:
b.setSplitMode(SplitMode.SPLIT_RIGHT);
break;
case SPLIT_RIGHT:
b.setSplitMode(SplitMode.SPLIT_BOTTOM);
break;
case SPLIT_BOTTOM:
b.setSplitMode(SplitMode.SPLIT_LEFT);
break;
case SPLIT_LEFT:
b.setSplitMode(SplitMode.HIDDEN);
break;
case HIDDEN:
b.setSplitMode(SplitMode.SPLIT_TOP);
break;
}
label.setText(b.getSplitMode().toString());
});
StackPane.setAlignment(label, Pos.TOP_LEFT);
StackPane.setAlignment(rotate, Pos.TOP_RIGHT);
sp.getChildren().addAll(b, label, rotate);
primaryStage.setScene(new Scene(sp));
primaryStage.toFront();
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}