2

I have created a custom color picker control for JavaFX 8. It consists of six Sliders in a GridPane with respective Labels above them.

<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>

color picker

Now, when I narrow the picker, the labels' texts overflow.

narrowed color picker

What I'd like to happen here is that the texts would change to their first letters R, G, B, H, S, L instead of the clipped version with the ellipses.

Label's textOverrun property allows setting the overflow mode to the seven values defined in OverrunStyle, but none of those match what I'm looking for.

Looking inside the Label class, the displayed text is calculated by the Skin. In my JDK, this goes straight to com.sun.javafx.scene.control.skin.LabeledSkinBase.updateDisplayedText() which then calls com.sun.javafx.scene.control.skin.Utils.computeClippedText(). There's really no easy way to modify this stuff by extending Label since it's non-portable; one would have to reimplement the entire Skin, which is basically the full implementation of the Label's UI.

Is there a portable way to make the Labels' texts contract to a single character when overflowing other than implementing your own Skin?

UPDATE: I implemented @VGR's answer as a reusable class. You can get it here: https://bitbucket.org/snippets/Pietu1998/LEqXo

Community
  • 1
  • 1
PurkkaKoodari
  • 6,703
  • 6
  • 37
  • 58

2 Answers2

2

This isn’t quite what you asked for—using OverrunStyle to accomplish your goal—but it does create the same effect:

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;
}
VGR
  • 40,506
  • 4
  • 48
  • 63
1

hope this helps (but it needs some improvements)

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;

    }

}
guleryuz
  • 2,714
  • 1
  • 15
  • 19