JavaFX:在文本下方居中显示 MenuButton 的箭头

JavaFX: Display the arrow of a MenuButton centered below the text

是否可以更改 MenuButton 箭头的位置,使其在其文本内容下方居中显示?

为了说明我的问题,这里有一张图片:

我尝试将 MenuButton 中的灰色箭头移动到红色箭头显示的位置。

正如 Uluk Biy 建议的那样,但你想改变箭头的位置 Exp : -fx-填充: 0 20 0 0

用于右填充

我能想到的最好的方法是取消默认箭头的填充并包含自定义箭头。原因是您正在尝试更改无法控制的 MenuButton 的默认布局,无法通过 CSS 更改来处理它。

所以大致思路如下:

  • 将默认箭头窗格和箭头的填充设置为 0。
  • 构建具有自定义图形的自定义 MenuButton,以模仿所需的布局。

请查看下面的演示:

import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Group;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.control.ContentDisplay;
import javafx.scene.control.Label;
import javafx.scene.control.MenuButton;
import javafx.scene.control.MenuItem;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.scene.shape.Circle;
import javafx.stage.Stage;

public class MenuButtonArrowDemo extends Application {

    @Override
    public void start(Stage stage) {
        MenuButton button1 = new MenuButton("First");
        Circle graphic = new Circle(5);
        graphic.setStyle("-fx-fill:red");
        button1.setGraphic(graphic);
        button1.setContentDisplay(ContentDisplay.TOP);
        MenuItem f1 = new MenuItem("First Sub Item");
        button1.getItems().add(f1);

        Circle dot = new Circle(5);
        dot.setStyle("-fx-fill:red");
        MenuButton button2 = new CustomMenuButton("First", dot);
        MenuItem f2 = new MenuItem("First Sub Item");
        button2.getItems().add(f2);

        HBox hbox = new HBox(button1, button2);
        hbox.setPadding(new Insets(10));
        hbox.setSpacing(10);
        BorderPane root = new BorderPane();
        root.setTop(hbox);
        Scene scene = new Scene(root, 350, 200);
        stage.setScene(scene);
        stage.setTitle("MenuButton Arrow");
        stage.show();
    }

    class CustomMenuButton extends MenuButton {
        StackPane graphicContainer = new StackPane();
        Label label = new Label();

        public CustomMenuButton(String text) {
            label.setText(text);
            init();
        }

        public CustomMenuButton(String text, Node graphic) {
            label.setText(text);
            graphicContainer.getChildren().add(graphic);
            init();
        }

        private void init() {
            getStyleClass().add("custom-menu-button"); //  to control the styling from css file
            StackPane myArrow = new StackPane();
            // You can set this styling in css file
            myArrow.setStyle("-fx-background-color: -fx-mark-highlight-color, -fx-mark-color;-fx-background-insets: 0 0 -1 0, 0;-fx-padding: 2px 4px 2px 4px;-fx-shape: \"M 0 0 h 7 l -3.5 4 z\"");
            StackPane arrowPane = new StackPane(new Group(myArrow));
            arrowPane.setPadding(new Insets(0, 6, 4, 6));
            VBox buttonGraphic = new VBox(graphicContainer, label, arrowPane);
            buttonGraphic.setAlignment(Pos.CENTER);
            buttonGraphic.setSpacing(5);
            setGraphic(buttonGraphic);
            setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
        }

        @Override
        protected void layoutChildren() {
            super.layoutChildren();
            // You can set this styling in css file
            lookup(".arrow-button").setStyle("-fx-padding:0px;");
            lookup(".arrow").setStyle("-fx-padding:0px;");
        }
    }
}