为标签定义自定义溢出样式
Defining a custom overrun style for a Label
我为 JavaFX 8 创建了一个自定义颜色选择器控件。它由 GridPane
中的六个 Slider
组成,在它们上面分别有 Label
s。
<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>
现在,当我缩小选择器时,标签的文本会溢出。
我想在这里发生的是文本将更改为它们的第一个字母 R
、G
、B
、H
、S
, L
而不是带有省略号的剪辑版本。
Label
的 textOverrun
property allows setting the overflow mode to the seven values defined in OverrunStyle
,但其中 none 符合我的要求。
在Label
class里面看,显示的文字是由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;
}
我为 JavaFX 8 创建了一个自定义颜色选择器控件。它由 GridPane
中的六个 Slider
组成,在它们上面分别有 Label
s。
<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>
现在,当我缩小选择器时,标签的文本会溢出。
我想在这里发生的是文本将更改为它们的第一个字母 R
、G
、B
、H
、S
, L
而不是带有省略号的剪辑版本。
Label
的 textOverrun
property allows setting the overflow mode to the seven values defined in OverrunStyle
,但其中 none 符合我的要求。
在Label
class里面看,显示的文字是由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
希望这对您有所帮助(但需要一些改进)
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;
}