简体   繁体   English

JavaFX 2:包含文本的可调整大小的矩形

[英]JavaFX 2: resizable rectangle containing text

I want to display a rectangle that contains a text/label. 我想显示一个包含文本/标签的矩形。 For this purpose I created a stackpane and added a rectangle and a label to it. 为此,我创建了一个堆栈窗格,并为其添加了一个矩形和一个标签。 However the text/label is not centered correctly. 但是,文本/标签未正确居中。 It is placed outside of the rectangle (to the left). 它放置在矩形的外部(左侧)。 This is the code I am currently using: 这是我当前正在使用的代码:

createRectangle(String name) {
   pane = new StackPane();
   text = new Label(name);
   rect = new Rectangle();
   // bind rectangle width to text width and add 10 
   rect.widthProperty().bind(text.widthProperty().add(10));
   rect.heightProperty().bind(text.heightProperty().add(10));

   // add to stackpane
   pane.getChildren().addAll(rect,text);

   // display stackpane
   getChildren().add(pane)
}

I have tried binding the xProperty() and yProperty() of the rectangle, changing the alignment of the stackpane (setAlignment(Pos.CENTER)) and other things, but without success. 我尝试绑定矩形的xProperty()和yProperty(),更改堆栈窗格的对齐方式(setAlignment(Pos.CENTER))等,但是没有成功。

When I use a fixed rectangle size (eg new Rectangle(30,30)) and do not use the bindings, the label is centered correctly within the rectangle. 当我使用固定的矩形大小(例如,新的Rectangle(30,30))并且不使用绑定时,标签将在矩形内正确居中。 However, the rectangle's size needs to adjust depending on the label size: 但是,矩形的大小需要根据标签大小进行调整:

// label is placed correctly in the center of the rectangle
createRectangle(String name) {
   pane = new StackPane();
   text = new Label(name);
   rect = new Rectangle(30,30);

   // add to stackpane
   pane.getChildren().addAll(rect,text);

   // display stackpane
   getChildren().add(pane)
}

For a Background Sized to the Label 对于标签大小的背景

Just use CSS directly on the Label, you don't need any other nodes. 只需直接在Label上使用CSS,就不需要任何其他节点。

Label label = new Label("Sally collects seashells on the seashore");
label.setStyle("-fx-background-color: coral; -fx-padding: 10px;");

The padding can be used to adjust the size of the rectangular background area around the label. 填充可用于调整标签周围矩形背景区域的大小。

固定标签

For a Resizable Background 对于可调整大小的背景

You don't need a Rectangle node, put the label in a StackPane and set a background on the StackPane: 您不需要Rectangle节点,将标签放在StackPane中,并在StackPane上设置背景:

Label label = new Label("Sally collects seashells on the seashore");
StackPane centeredLabel = new StackPane(label);
centeredLabel.setStyle("-fx-background-color: coral;");

居中标签

Executable sample 可执行样本

import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;

public class LabelBackground extends Application {
    @Override
    public void start(Stage stage) throws Exception {
        Label label = new Label("Sally collects seashells on the seashore");
        StackPane centeredLabel = new StackPane(label);
        centeredLabel.setStyle("-fx-background-color: coral;");

        StackPane root = new StackPane(centeredLabel);
        root.setPadding(new Insets(10));

        stage.setScene(new Scene(root));
        stage.show();
    }

    public static void main(String[] args) {
        Application.launch(args);
    }
} 

Note: Inline styles in this answer are just for easy demonstration purposes, best practice is to use a CSS stylesheet for CSS style definitions. 注意:此答案中的内联样式仅用于简单演示目的,最佳实践是将CSS样式表用于CSS样式定义。

I also want to use other shapes (especially rounded rectangles and circles) instead of plain rectangles. 我还想使用其他形状(尤其是圆角的矩形和圆形)而不是普通的矩形。 Is this achievable by styling the stackpane or the label itself as proposed in your answer? 是否可以通过按照答案中的建议设计样式或标签本身来实现?

Yes, anything which derives from Region (which includes layout panes such as StackPane and Controls such as Label), can be styled pretty extensively via CSS. 是的,任何从Region派生的东西(包括诸如StackPane之类的布局窗格和诸如Label之类的控件)都可以通过CSS进行广泛的样式设置。

To get a rounded background, you can use -fx-background-radius . 要获取圆形背景,可以使用-fx-background-radius

To get an arbitrary shaped background, you can use fx-shape , though you may find it tricky to position your text within the arbitrarily shaped background. 要获得任意形状的背景,可以使用fx-shape ,但是将文本放置在任意形状的背景中可能会很麻烦。

You can also write a shape in code and use bindings to make things fit inside it as you originally tried in your question. 您还可以在代码中编写形状,并使用绑定使事物适合形状,就像您最初在问题中尝试的那样。

If things need a lot of fine-tuning then you can subclass region and over-ride the layoutChildren method to perform precise layout calculations for all of the children inside that method (this is the way that most of the in-built JavaFX controls handle layouts in their skin classes). 如果需要大量微调,则可以对region进行子类化,并覆盖layoutChildren方法,以对该方法内的所有子代执行精确的布局计算(这是大多数内置JavaFX控件处理布局的方式)在他们的皮肤课程中)。

Anyway, a seemingly simple question doesn't always have a simple answer, because there ends up lots of variations both in the way you can do things and many subtle differences in what you might want to do, such as how to handle wrapped text, insets, whether to elide the text beyond a minimum size, etc. 无论如何,一个看似简单的问题并不总是有一个简单的答案,因为在做事方式和可能要做的事情上存在许多细微的差异,例如如何处理包装好的文字,插图,是否将文本超出最小尺寸等等。

However, for the most common tasks of rectangular or rounded rectangular backgrounds, I'd just stick to using CSS styles directly on labels. 但是,对于矩形或圆形矩形背景的最常见任务,我只是坚持直接在标签上使用CSS样式。 By using style sheets, you can easily completely change the app style for your labels. 通过使用样式表,您可以轻松地完全更改标签的应用样式。

Here is a more extensive, overkill sample: 这是一个更广泛的,过度使用的示例:

lotastyles

LabelBackground.java LabelBackground.java

import javafx.application.Application;
import javafx.beans.binding.DoubleBinding;
import javafx.geometry.*;
import javafx.scene.*;
import javafx.scene.control.Label;
import javafx.scene.layout.*;
import javafx.scene.shape.Ellipse;
import javafx.stage.Stage;

public class LabelBackground extends Application {
    @Override
    public void start(Stage stage) throws Exception {
        Pane starLabel = labelOnStyledBackground(
                "Practical Principles of Plain and Perfect Pronunciation.",
                "star-label"
        );

        StackPane labelOnResizableBackground = labelOnStyledBackground(
                "Sally collects seashells on the seashore",
                "resizable-background"
        );
        labelOnResizableBackground.setPrefHeight(60);

        Label squareLabel = createLabel(
                "Betty Botter bought a bit of butter.",
                "square-label"
        );

        Label roundedLabel = createLabel(
                "Peter Piper picked a peck of pickled peppers.",
                "rounded-label"
        );

        Node ellipticalLabel = createEllipticalLabel(
                "Round and round the rugged rock the ragged rascal ran.",
                "elliptical-label"
        );

        VBox root = new VBox(
                10,
                starLabel,
                labelOnResizableBackground,
                squareLabel,
                roundedLabel,
                ellipticalLabel
        );
        VBox.setVgrow(labelOnResizableBackground, Priority.SOMETIMES);
        root.setAlignment(Pos.TOP_CENTER);
        root.setPadding(new Insets(10));

        Scene scene = new Scene(root);
        scene.getStylesheets().add(
                LabelBackground.class.getResource(
                        "label-styles.css"
                ).toExternalForm()
        );
        stage.setScene(scene);
        stage.setTitle("Resize me!");
        stage.show();
    }

    private Label createLabel(String text, String styleClass) {
        Label label = new Label(text);
        label.getStyleClass().add(styleClass);

        return label;
    }

    private StackPane labelOnStyledBackground(String text, String styleClass) {
        Label label = new Label(text);
        StackPane container = new StackPane(label);
        container.getStyleClass().add(styleClass);

        return container;
    }

    private Group createEllipticalLabel(String text, String styleClass) {
        final double INSET = 20;

        Label label = new Label(text);

        Ellipse ellipse = new Ellipse();
        ellipse.getStyleClass().add("ellipse");

        DoubleBinding halfWidth  = label.widthProperty().divide(2).add(INSET);
        DoubleBinding halfHeight = label.widthProperty().divide(4).add(INSET);

        ellipse.radiusXProperty().bind(halfWidth);
        ellipse.radiusYProperty().bind(halfHeight);

        ellipse.centerXProperty().bind(halfWidth);
        ellipse.centerYProperty().bind(halfHeight);

        label.setLayoutX(INSET);
        label.layoutYProperty().bind(halfHeight.subtract(label.heightProperty().divide(2)));

        Group group = new Group(ellipse, label);
        group.getStyleClass().add(styleClass);

        return group;
    }

    public static void main(String[] args) {
        Application.launch(args);
    }
} 

label-styles.css label-styles.css

.root {
    -fx-font-size: 16px;
}

.rounded-label {
    -fx-background-color: cadetblue;
    -fx-padding: 10px;
    -fx-background-radius: 10px;
}

.square-label {
    -fx-background-color: plum;
    -fx-padding: 10px;
}

.star-label {
    -fx-background-color: gold;
    -fx-padding: 120px;
    /* shape courtesy of Smiffy's star place: http://www.smiffysplace.com/stars.html */
    -fx-shape: "M 0.000 20.000 L 23.511 32.361 L 19.021 6.180 L 38.042 -12.361 L 11.756 -16.180 L 0.000 -40.000 L -11.756 -16.180 L -38.042 -12.361 L -19.021 6.180 L -23.511 32.361 L 0.000 20.000";
}

.resizable-background {
    -fx-background-color: coral;
}

.elliptical-label .ellipse {
    -fx-fill: lightpink;
}

If you are super-keen for further samples, look at the way the QuoteMaker app handles styling of resizable label backgrounds. 如果您非常喜欢其他示例,请查看QuoteMaker应用处理可调整大小的标签背景样式的方式。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM