为标签定义自定义溢出样式

Defining a custom overrun style for a Label

我为 JavaFX 8 创建了一个自定义颜色选择器控件。它由 GridPane 中的六个 Slider 组成,在它们上面分别有 Labels

<GridPane vgap="10" hgap="10">
    <Label labelFor="${redSlider}" text="Red"
           GridPane.rowIndex="0" GridPane.columnIndex="0" GridPane.halignment="CENTER"/>
    <!-- 5 more labels -->
    <Slider max="255" orientation="VERTICAL" fx:id="redSlider" id="redSlider"
            GridPane.rowIndex="1" GridPane.columnIndex="0" GridPane.vgrow="ALWAYS"
            GridPane.hgrow="ALWAYS" GridPane.halignment="CENTER"/>
    <!-- 5 more Sliders -->
</GridPane>

现在,当我缩小选择器时,标签的文本会溢出。

我想在这里发生的是文本将更改为它们的第一个字母 RGBHS, L 而不是带有省略号的剪辑版本。

LabeltextOverrun property allows setting the overflow mode to the seven values defined in OverrunStyle,但其中 none 符合我的要求。

Labelclass里面看,显示的文字是由Skin计算出来的。在我的 JDK 中,它直接进入 com.sun.javafx.scene.control.skin.LabeledSkinBase.updateDisplayedText(),然后调用 com.sun.javafx.scene.control.skin.Utils.computeClippedText()。确实没有简单的方法可以通过扩展 Label 来修改这些东西,因为它是不可移植的;必须重新实现整个 Skin,这基本上是 Label 的 UI.

的完整实现

除了实现您自己的 Skin 之外,是否有 可移植 方法使 Label 的文本在溢出时收缩为单个字符?

更新: 我实现了 @VGR's as a reusable class. You can get it here: https://bitbucket.org/snippets/Pietu1998/LEqXo

希望这对您有所帮助(但需要一些改进)

import javafx.application.Platform;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.control.SkinBase;
import javafx.scene.layout.HBox;
import javafx.scene.layout.StackPane;
import javafx.scene.text.Text;
import javafx.stage.Stage;

public class Test extends javafx.application.Application {

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

    @Override
    public void start(Stage primaryStage) {
        primaryStage.setTitle("Test");

        HBox root = new HBox();

        root.getChildren().add(getLabel("Aaaaa"));
        root.getChildren().add(getLabel("Bbbbbbbbb"));
        root.getChildren().add(getLabel("Cccccccccccccccccc"));
        root.getChildren().add(getLabel("Ddddddddddddd"));
        root.getChildren().add(getLabel("Eeeeeeeeee"));
        root.getChildren().add(getLabel("Fffff"));

        primaryStage.setScene(new Scene(root, 500, 250));
        primaryStage.show();
    }

    private StackPane getLabel(String text) {

        final Label label = new Label(text);
        final Label gLabel = new Label(text.substring(0, 1));

        // should run after label become visible
        Platform.runLater(() -> {
            for(Node node : ((SkinBase<Label>)label.getSkin()).getChildren()) {
                if(node instanceof Text) {
                    ((Text)node).textProperty().addListener((e, o, n) -> {
                        gLabel.setVisible(!label.getText().equals(n));
                        label.setVisible(!gLabel.isVisible());
                    });
                }
            }
        });

        gLabel.setStyle("-fx-border-color: red");
        gLabel.setVisible(false);

        StackPane pane = new StackPane(label, gLabel);

        return pane;

    }

}

这不是您所要求的——使用 OverrunStyle 来实现您的目标——但它确实产生了相同的效果:

public static Node createCondensingLabel(String regularText,
                                         String condensedText) {

    Label regularLabel = new Label(regularText);
    Label condensedLabel = new Label(condensedText);

    StackPane pane = new StackPane(regularLabel, condensedLabel);

    BooleanBinding fullyVisible = Bindings.createBooleanBinding(() ->
        regularLabel.getWidth() >=
            regularLabel.prefWidth(regularLabel.getHeight()),
        regularLabel.widthProperty());

    regularLabel.visibleProperty().bind(fullyVisible);
    condensedLabel.visibleProperty().bind(fullyVisible.not());

    return pane;
}