Изменение размера метки JavaFX при переполнении
У меня есть Метка в GridPane в TitledPane. Я хочу, чтобы он постепенно уменьшался на 0,05 мкм, если он переполнен, поэтому три точки ("Длинная метка...") не отображаются -> "Длинная метка" в маленьком значении.
IsOverrun()- метод для Label был бы хорош, но JavaFX этого не обеспечивает, и жизнь не является идеей.
Так что мой обходной путь пока что
Bounds tpBounds = tPane.getBoundsInLocal();
Bounds lblBounds = label.getBoundsInLocal();
Double fontSize = 1.0;
while (tpBounds.getWidth() < lblBounds.getWidth() && fontSize > 0.5) {
fontSize = fontSize-0.05;
label.setStyle("-fx-font-size: "+fontSize+"em;");
System.out.println(fontSize+" "+tpBounds.getWidth()+" "+lblBounds.getWidth());
}
Проблема: во время цикла while bounds.getWidth() всегда показывает исходную ширину. "Новая" ширина с новым размером шрифта не обновляется достаточно быстро, чтобы быть пойманной условием while, поэтому размер шрифта становится все меньше и меньше.
Любые решения?
редактировать
Я спрашиваю чаще: действительно ли это сложно сделать ярлык сам по себе уменьшенным, пока он не уместится без усечения?!
3 ответа
Это хак, вдохновленный внутренним API.
JavaFX использует com.sun.javafx.scene.control.skin.Utils
Класс для различных текстовых расчетов. Это также включает в себя подсчет переполненных текстов в зависимости от того, на сколько обрезается исходный текст и где показывается многоточечный текст и т. Д.
Для не обернутых и не многострочных текстов меток в этом классе используются только 3 метода:
static String computeClippedText(Font font, String text, double width, OverrunStyle type, String ellipsisString)
static double computeTextWidth(Font font, String text, double wrappingWidth) {...}
static int computeTruncationIndex(Font font, String text, double width) {...}
Поскольку этот класс является внутренним API, я просто скопировал эти 3 метода (вместе с необходимыми переменными класса) в свой собственный класс Utils и использовал его как:
@Override
public void start( Stage primaryStage )
{
final Label label = new Label( "Lorem Ipsum is simply dummy long text of the printing and typesetting industry" );
label.setFont( Font.font( 10 ) );
System.out.println( "originalText = " + label.getText() );
Platform.runLater( () ->
{
Double fontSize = label.getFont().getSize();
String clippedText = Utils.computeClippedText( label.getFont(), label.getText(), label.getWidth(), label.getTextOverrun(), label.getEllipsisString() );
Font newFont = label.getFont();
while ( !label.getText().equals( clippedText ) && fontSize > 0.5 )
{
System.out.println( "fontSize = " + fontSize + ", clippedText = " + clippedText );
fontSize = fontSize - 0.05;
newFont = Font.font( label.getFont().getFamily(), fontSize );
clippedText = Utils.computeClippedText( newFont, label.getText(), label.getWidth(), label.getTextOverrun(), label.getEllipsisString() );
}
label.setFont( newFont );
} );
Scene scene = new Scene( new VBox(label), 350, 200 );
primaryStage.setScene( scene );
primaryStage.show();
}
Исходя из ваших требований вы можете упростить логику и улучшить время расчета computeClippedText()
метод дальше.
Еще один способ, который работает:
.setMinHeight(Region.USE_PREF_SIZE)
Просто и намного проще, чем рассчитать.
Решение:
fontVerkleinerung(lblXYZ); //call resizing at beginning
lblXYZ.styleProperty().addListener((observable, oldV, newV) -> {
fontVerkleinerung(lblXYZ); //check size again if resized
});
private void fontVerkleinerung(Label label) {
Platform.runLater(() -> {
tpBounds = tPane.getBoundsInLocal();
if (label.getBoundsInLocal().getWidth()>tpBounds.getWidth() && !fontSizeFits) {
fontSize = fontSize-0.02;
label.setStyle("-fx-font-size: "+fontSize+"em;");
}
if (label.getBoundsInLocal().getWidth()<=tpBounds.getWidth() && !fontSizeFits) {
fontSizeFits = true;
}
});
}
Этот обходной путь не удовлетворяет на 100%, GUI страдает из-за медленной графической скорости обновления на label.setStyle("...");
Требуется несколько мс, пока не включится слушатель styleProperty.
Я пытался исправить это в течение нескольких недель, всегда находил вероятное решение, но оно не работало. Я надеюсь, что кто-то получит прибыль от этого поста.
Эта функция творит чудеса, в основном вычисляет размер вычисления текущей ширины метки preferredWidth(может быть изменен в зависимости от настройки метки), и если она больше, то уменьшите шрифт на 0,5 (также необязательно, может быть пользовательское значение).
примечание: рассмотреть также установить условие, если шрифт меньше 0,5, чтобы избежать того, что шрифт не достигнет нуля. Также может быть преобразован с помощью while вместо рекурсивной функции и также будет оптимальным, я установлю оба на всякий случай
public Label ResizeTextIfOverrunRecursive(Label label, String text, double size) throws Exception {
FontLoader fontLoader = Toolkit.getToolkit().getFontLoader();
label.setFont(Font.font(size));
double font = label.getFont().getSize();
label.setStyle("-fx-font-size:" + (font) +"px;");
label.applyCss();
label.layout();
label.setText(text);
double prefWidth = label.getPrefWidth();
if (fontLoader.computeStringWidth(label.getText(), label.getFont()) > prefWidth){
return ResizeTextIfOverrunRecursive(label, text, size - 0.5);
} else return label;
}
public void ResizeTextIfOverrunItaration(Label label, String text, double size) throws Exception {
FontLoader fontLoader = Toolkit.getToolkit().getFontLoader();
label.setFont(Font.font(size));
double font = label.getFont().getSize();
label.setStyle("-fx-font-size:" + (font) +"px;");
label.applyCss();
label.layout();
double prefWidth = label.getPrefWidth();
while (fontLoader.computeStringWidth(label.getText(), label.getFont()) > prefWidth){
font -= 0.5;
label.setStyle("-fx-font-size:" + (font) +"px;");
label.applyCss();
label.layout();
}
label.setText(text);
}