【问题标题】:Auto-expand TextField to fit text自动扩展 TextField 以适应文本
【发布时间】:2019-12-19 18:52:17
【问题描述】:

我想创建一个随着输入更多文本而水平扩展的文本字段。

prefColumnCount 属性绑定到TextField 中的文本长度后,它的大小会随着文本变长而增加。但是,插入符号的位置不会更新,并且无论文本长度如何,它都会卡在同一位置。用户必须手动将插入符号移到前面才能正确显示。

图片:

输入一些文本后的样子,文本没有占据整个文本域:

移动文本开头的插入符号后:

这是我当前的代码:

TextField textField = new TextField();
textField.prefColumnCountProperty().bind(textField.textProperty().length());
setHgrow(textField, Priority.ALWAYS);

我该如何解决这个问题?任何帮助表示赞赏!

【问题讨论】:

  • "但是,插入符号的位置没有更新,并且无论文本长度如何,它都会卡在同一位置。" - 鉴于following code,无法重现。键入时插入符号正确地向右移动。

标签: java javafx


【解决方案1】:

此示例在其自己的 css 样式场景中使用单独的测量文本变量来计算对 TextField 首选大小的更新,以便它的首选大小根据需要扩展和缩小。

import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.scene.*;
import javafx.scene.control.TextField;
import javafx.scene.layout.*;
import javafx.scene.text.Text;
import javafx.stage.Stage;

public class MagicExpander extends Application {

    @Override
    public void start(Stage stage) throws Exception {
        TextField textField = new ExpandingTextField();

        Pane layout = new VBox(textField);
        layout.setPadding(new Insets(10));

        stage.setScene(new Scene(layout, 600, 40));
        stage.show();
    }

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

    static class ExpandingTextField extends TextField {
        private static int MAGIC_PADDING = 20;

        private Text measuringText = new Text();
        // To allow potential css formatting to work for the text,
        // it is required that text be placed in a Scene,
        // even though we never explicitly use the scene.
        private Scene measuringScene = new Scene(new Group(measuringText));

        ExpandingTextField() {
            super();
            setPrefWidth(MAGIC_PADDING);
            setMinWidth(MAGIC_PADDING);
            setMaxWidth(USE_PREF_SIZE);

            // note if the text in your text field is styled, then you should also apply the
            // a similar style to the measuring text here if you want to get an accurate measurement.

            textProperty().addListener(observable -> {
                measuringText.setText(getText());
                setPrefWidth(measureTextWidth(measuringText) + MAGIC_PADDING);
            });
        }

        private double measureTextWidth(Text text) {
            text.applyCss();
            return text.getLayoutBounds().getWidth();
        }
    }
}

【讨论】:

    【解决方案2】:

    问题来自 caret,它以图形方式更新其位置,就好像他在一个静态区域中一样;一旦定义了 TextField 的 prefWidth 属性,插入符号就不会从文本字段中消失。

    当我写下内容直到它到达右侧时,插入符号应该超出字段,这是不可能的;它似乎在虚拟墙的前面。结果,所有文本内容都被“翻译”到左侧,以使插入符号位于同一位置。令人费解的是,您的绑定效果很好,所以TextField 的宽度会随着您添加文本而不断增长...

    在您的情况下,我建议您每次在文本字段中输入内容时刷新插入符号位置。将此 EventHandler 添加到您的 TextField 实例化中:

    textField.addEventHandler(KeyEvent.KEY_PRESSED, ke -> {
        if (ke.getCode() != KeyCode.DELETE) {
            textField.positionCaret(0);
            textField.positionCaret(textField.getText().length());
        }
    });
    

    附加说明

    您的绑定仅适用于 等宽 字体,例如 Consolas 或 Courier New;如果您使用 Arial 或 Calibri 等字体,prefWidth 将无法正确计算。您必须导入 com.sun.javafx.tk 并使用 FontMetricsToolKit 类。

    您将拥有类似以下内容的东西,而不是您的绑定:

    FontMetrics fm = Toolkit.getToolkit().getFontLoader().getFontMetrics(textField.getFont());
    textField.textProperty().addListener((bean_p, old_p, new_p) -> {
        Insets in = textField.getInsets();
        textField.setPrefWidth(fm.computeStringWidth(new_p) + in.getLeft() + in.getRight());
    });
    

    希望对你有用:)

    【讨论】:

    • 这是一个有趣的解决方法。不过,还是有一道小而明显的“隐形墙”,打字速度快时有时会闪烁。不管怎样,谢谢你的回复!
    • 你是对的,有一些像素丢失以完美适合文本;也许我们必须考虑TextField 的边框厚度,但我不确定。至于闪烁现象,我很惊讶,因为我在快速打字或按同一键多秒时都没有这个问题。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-09-20
    • 2023-03-09
    • 2011-12-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多