JavaFX SplitMenuButton设置箭头的位置 [英] JavaFX SplitMenuButton setting the position of the arrow

查看:575
本文介绍了JavaFX SplitMenuButton设置箭头的位置的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

正常的SplitMenuButton如下所示:
标准SplitMenuButton

A normal SplitMenuButton looks like this: Standard SplitMenuButton

我想改变JavaFX SplitMenuButton中箭头的位置但是如果有一个配置会给我这样的东西就无法解决:
SplitMenuButton,底部带箭头

I would like to change the location of the arrow in a JavaFX SplitMenuButton but cannot work out if there is even a configuration that will give me something like this: SplitMenuButton with arrow on bottom

是这可能还是我需要创建一个定制版本的分割菜单按钮?

Is this possible or will I need to create a bespoke version of split menu button?

推荐答案

在玩JavaFX SplitMenuButton后我无法做到找到任何方法轻松重现我需要的东西(默认右边的菜单箭头)。我创建了一个按钮类,允许箭头按钮放在主按钮的任何一侧(甚至隐藏)。这个课程没有得到完善,但能胜任。这个示例类的优点是箭头侧可以动态更改。

After playing with the JavaFX SplitMenuButton I could not find any way to easily reproduce what I need (menu arrow on side other than default right). I created a button class that allows the arrow button to be placed on any side of the main button( or even hidden). The class is not polished but does the job. The great thing about this sample class is that the arrow side can be changed dynamically.

课程代码:

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类创建额外的伪类以为每一方启用特殊格式。

MyButton class creates additional pseudo classes to enable special formatting for each side.

示例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;
}

示例应用程序测试按钮。

Sample Application to test button.

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

这篇关于JavaFX SplitMenuButton设置箭头的位置的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆