简体   繁体   English

JavaFX TextField调整大小到文本长度?

[英]Javafx textfield resize to text length?

Hello guys I am building a chat server where I use a textfield on the screen to type in the chat message that the user writes, the idea is that it works like a bubble over a persons head when he types a message. 大家好,我正在构建一个聊天服务器,在该服务器上,我使用屏幕上的文本字段键入用户编写的聊天消息,其想法是,当他键入消息时,它就像人头上的气泡一样。

my question is in order to not make a textbox that is too large or too small is there a way to make the textbox resize (trim if you will) so it adjust to the text written in the textfield? 我的问题是为了不使文本框太大或太小,是否有办法调整文本框的大小(如果可以的话,请进行调整),使其适应文本字段中写入的文本?

PS I'm using JavaFx scenebuilder to do all of this. PS我正在使用JavaFx scenebuilder来完成所有这些工作。

You can use computeTextWidth method in the com.sun.javafx.scene.control.skin.Utils . 您可以在com.sun.javafx.scene.control.skin.Utils使用computeTextWidth方法。 the method is used in javafx.scene.control.Label class to calculate the minimum width for label content. 该方法在javafx.scene.control.Label类中使用,以计算标签内容的最小宽度。

I solved my problem as below: 我解决了如下问题:

field.textProperty().addListener(new ChangeListener<String>() {
        @Override
        public void changed(ObservableValue<? extends String> ob, String o,
                String n) {
            // expand the textfield
            field.setPrefWidth(TextUtils.computeTextWidth(field.getFont(),
                    field.getText(), 0.0D) + 10);
        }
    });

I have added a listener to textProperty , and with every text change i change the prefWidth of textfield. 我在textProperty添加了一个侦听textProperty ,并且每次更改文本时,我都会更改textfield的prefWidth

Note: as long as the Utils.computeTextWidth() is not public , I have copied the source code to a new class ( TextUtils ). 注意:只要Utils.computeTextWidth() 不公开 ,我Utils.computeTextWidth()源代码复制到一个新类( TextUtils )。

Here is the full source code: 这是完整的源代码:

package me.jone30rw.fxcontrol;

import javafx.scene.text.Font;
import javafx.scene.text.Text;
import javafx.scene.text.TextBoundsType;

public class TextUtils {

    static final Text helper;
    static final double DEFAULT_WRAPPING_WIDTH;
    static final double DEFAULT_LINE_SPACING;
    static final String DEFAULT_TEXT;
    static final TextBoundsType DEFAULT_BOUNDS_TYPE;
    static {
        helper = new Text();
        DEFAULT_WRAPPING_WIDTH = helper.getWrappingWidth();
        DEFAULT_LINE_SPACING = helper.getLineSpacing();
        DEFAULT_TEXT = helper.getText();
        DEFAULT_BOUNDS_TYPE = helper.getBoundsType();
    }

    public static double computeTextWidth(Font font, String text, double help0) {
        // Toolkit.getToolkit().getFontLoader().computeStringWidth(field.getText(),
        // field.getFont());

        helper.setText(text);
        helper.setFont(font);

        helper.setWrappingWidth(0.0D);
        helper.setLineSpacing(0.0D);
        double d = Math.min(helper.prefWidth(-1.0D), help0);
        helper.setWrappingWidth((int) Math.ceil(d));
        d = Math.ceil(helper.getLayoutBounds().getWidth());

        helper.setWrappingWidth(DEFAULT_WRAPPING_WIDTH);
        helper.setLineSpacing(DEFAULT_LINE_SPACING);
        helper.setText(DEFAULT_TEXT);
        return d;
    }
}

In JavaFX 8, there is a solution for that, here is the code: 在JavaFX 8中,有一个解决方案,代码如下:

TextField tf = new TextField();
// Set Max and Min Width to PREF_SIZE so that the TextField is always PREF
tf.setMinWidth(Region.USE_PREF_SIZE);
tf.setMaxWidth(Region.USE_PREF_SIZE);
tf.textProperty().addListener((ov, prevText, currText) -> {
    // Do this in a Platform.runLater because of Textfield has no padding at first time and so on
    Platform.runLater(() -> {
        Text text = new Text(currText);
        text.setFont(tf.getFont()); // Set the same font, so the size is the same
        double width = text.getLayoutBounds().getWidth() // This big is the Text in the TextField
                + tf.getPadding().getLeft() + tf.getPadding().getRight() // Add the padding of the TextField
                + 2d; // Add some spacing
        tf.setPrefWidth(width); // Set the width
        tf.positionCaret(tf.getCaretPosition()); // If you remove this line, it flashes a little bit
    });
});
tf.setText("Hello World!");
  • In JavaFX 2.2 this code works with little limitations. 在JavaFX 2.2中,此代码几乎没有限制。 You can't set the Font(so if you do not use the std-font, you must set it manually). 您无法设置字体(因此,如果不使用标准字体,则必须手动设置)。
  • You can't get the padding from a TextField(so if you know the padding, write it hardcoded). 您无法从TextField获取填充(因此,如果您知道该填充,请对其进行硬编码)。

Happy Coding, 快乐编码,
Kalasch 卡拉施

从JavaFX 8开始,这是最简单的:

textField.prefColumnCountProperty().bind(textField.textProperty().length());

It is time to do some coding behind the scenes(builder) :). 现在该在幕后(builder):)进行一些编码了。
The following code chunk is not a neat solution but better than none. 以下代码块不是一个很好的解决方案,但总比没有好。 :) :)

// define width limits
textField.setMinWidth(50);
textField.setPrefWidth(50);
textField.setMaxWidth(400);
// add listner
textField.textProperty().addListener(new ChangeListener<String>() {
    @Override
    public void changed(ObservableValue<? extends String> observable, String oldValue, String newValue) {
        textField.setPrefWidth(textField.getText().length() * 7); // why 7? Totally trial number.
    }
});

No font dependent magic required if you use setPrefColumnCount 如果使用setPrefColumnCount,则不需要依赖字体的魔术

        tf.textProperty().addListener(new ChangeListener<String>() {
            @Override
            public void changed(ObservableValue<? extends String> ob, String o, String n) {
                tf.setPrefColumnCount(tf.getText().length() +1);
            }
        });

The best / easiest way to do this is to use JavaFX's "USE_COMPUTED_SIZE" option. 最好/最简单的方法是使用JavaFX的“ USE_COMPUTED_SIZE”选项。 You can either define it in the FXML, or programatically like this: 您可以在FXML中定义它,也可以像下面这样编程:

TextField textField = new TextField("hello");
textField.setPrefWidth(Control.USE_COMPUTED_SIZE);

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

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