JavaFX 切换菜单按钮

JavaFX Toggle MenuButton

是否有 JavaFX MenuButton(特别是 SplitMenuButton)也允许切换其选定状态? Swing 等效项是 OpenIDE JToggleButton,您可以将其创建为:

JToggleButton button = DropDownButtonFactory.createDropDownToggleButton(icon, menu)

因此,当用户单击操作区域时,除了触发与 ButtonBase.onAction 属性 关联的任何内容外,按钮的选定状态还应切换。单击箭头应该会按预期显示下拉菜单。

好的,我想我已经弄明白了。您需要创建一个名为 ToggleSplitMenuButton 的新 class 扩展自 SplitMenuButton:

import java.net.URL;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.BooleanPropertyBase;
import javafx.collections.ObservableList;
import javafx.css.PseudoClass;
import javafx.event.ActionEvent;
import javafx.scene.AccessibleAttribute;
import javafx.scene.control.MenuItem;
import javafx.scene.control.SplitMenuButton;

public class ToggleSplitMenuButton extends SplitMenuButton {

    private static final String STYLESHEET = "toggle-split-menu-button.css";

    /***************************************************************************
     *                                                                         *
     * Constructors                                                            *
     *                                                                         *
     **************************************************************************/

    public ToggleSplitMenuButton() {
        super();
        initialize();
    }

    public ToggleSplitMenuButton(MenuItem ... items) {
        super(items);
        initialize();
    }

    private void initialize() {
        Class<?> clazz = getClass();
        URL resource = clazz.getResource(STYLESHEET);
        String stylesheet = resource.toExternalForm();
        ObservableList<String> stylesheets = getStylesheets();
        stylesheets.add(stylesheet);
    }

    /***************************************************************************
     *                                                                         *
     * Properties                                                              *
     *                                                                         *
     **************************************************************************/
    /**
     * Indicates whether this toggle split menu button is selected. This can be
     * manipulated programmatically.
     */
    private BooleanProperty selected;

    public final void setSelected(boolean value) {
        selectedProperty().set(value);
    }

    public final boolean isSelected() {
        return selected == null ? false : selected.get();
    }

    public final BooleanProperty selectedProperty() {
        if (selected == null) {
            selected = new BooleanPropertyBase() {

                @Override
                protected void invalidated() {
                    final boolean selected = get();
                    pseudoClassStateChanged(PSEUDO_CLASS_SELECTED, selected);
                    notifyAccessibleAttributeChanged(AccessibleAttribute.SELECTED);
                }

                @Override
                public Object getBean() {
                    return ToggleSplitMenuButton.this;
                }

                @Override
                public String getName() {
                    return "selected";
                }
            };
        }
        return selected;
    }

    /***************************************************************************
     *                                                                         *
     * Methods                                                                 *
     *                                                                         *
     **************************************************************************/

    @Override
    public void fire() {
        if (!isDisabled()) {
            setSelected(!isSelected());
            fireEvent(new ActionEvent());
        }
    }

    /***************************************************************************
     *                                                                         *
     * Stylesheet Handling                                                     *
     *                                                                         *
     **************************************************************************/

    private static final PseudoClass PSEUDO_CLASS_SELECTED = PseudoClass.getPseudoClass("selected");
}

您还需要创建相应的样式表(称为 toggle-split-menu-button.css)以正确设置组件样式:

.split-menu-button:selected > .label {
    -fx-background-color:
        -fx-shadow-highlight-color,
        linear-gradient(to bottom, derive(-fx-outer-border, -20%), -fx-outer-border),
        linear-gradient(to bottom,
                derive(-fx-color, -22%) 0%,
                derive(-fx-color, -13%) 20%,
                derive(-fx-color, -11%) 50%);
}
.split-menu-button:selected > .arrow-button {
    -fx-background-color:
        -fx-shadow-highlight-color,
        linear-gradient(to bottom, derive(-fx-outer-border, -20%), -fx-outer-border),
        linear-gradient(to bottom,
                derive(-fx-color, -22%) 0%,
                derive(-fx-color, -13%) 20%,
                derive(-fx-color, -11%) 50%);
}
.split-menu-button:selected:focused > .label {
    -fx-background-color:
        -fx-shadow-highlight-color,
        linear-gradient(to bottom,
            derive(-fx-color, -22%) 0%,
            derive(-fx-color, -13%) 20%,
            derive(-fx-color, -11%) 50%),
        -fx-faint-focus-color,
        linear-gradient(to bottom,
            derive(-fx-color, -22%) 0%,
            derive(-fx-color, -13%) 20%,
            derive(-fx-color, -11%) 50%);
}
.split-menu-button:selected:focused > .arrow-button {
    -fx-background-color:
        -fx-shadow-highlight-color,
        linear-gradient(to bottom,
            derive(-fx-color, -22%) 0%,
            derive(-fx-color, -13%) 20%,
            derive(-fx-color, -11%) 50%),
        -fx-faint-focus-color,
        linear-gradient(to bottom,
            derive(-fx-color, -22%) 0%,
            derive(-fx-color, -13%) 20%,
            derive(-fx-color, -11%) 50%);
}