JavaFX - 限制 TextArea 行?

Posted

技术标签:

【中文标题】JavaFX - 限制 TextArea 行?【英文标题】:JavaFX - Limit TextArea rows? 【发布时间】:2015-09-20 11:55:31 【问题描述】:

在 Swing 中,我创建了一个自定义 Document,它能够确定和限制 TextArea 中的行数,无论是换行还是按下换行符。我希望在 FX 中找到类似的东西,但一直没能。有关如何处理限制允许的行数的任何建议?

编辑:这就是我试图找出 TextArea 中有多少换行的方法。最大的问题是让确切的宽度传递给 setWrappingWidth,因为 TextArea 的内容和边框似乎有一些填充。

Text helper = new Text();
helper.setText(text);
helper.setFont(getFont());
helper.wrappingWidthProperty().bind(widthBinding);
Font font = getFont();
FontMetrics fontMetrics = Toolkit.getToolkit().getFontLoader().getFontMetrics(font);
int preferredHeight = new Double(helper.getLayoutBounds().getHeight()).intValue();
int lineHeight = new Double(fontMetrics.getMaxAscent() + fontMetrics.getMaxDescent()).intValue();
System.err.println("preferredHeight / lineHeight: " + preferredHeight / lineHeight);
return preferredHeight / lineHeight;

【问题讨论】:

.setPrefRowCount(10); 不起作用吗?将 wrapText 设置为 true? textarea 也尊重它的区域,所以它会努力填充它,除非你用 maxsize 或其他东西限制它 据我所知,setPrefRowCount 和 setPrefColCount 仅影响 TextArea 的首选大小,不限制内容。 这根本没有任何意义。你不能指望在你 e 时线路会受到限制。 G。使文本区域更小。这是可用性的噩梦。这有什么用例? 大小没有变化。假设一个 TextArea 定义为 10 行和 40 列。首选大小已设置并且不会更改,但在某些情况下,我希望将文本限制为 400 个字符和/或 10 行。 Text 节点被用作确定当前首选大小的帮助器,以便确定字段中当前有多少换行(因为换行时不存在换行)。很抱歉我一直在远离我的电脑并试图跟上我的手机。 所以如果你有 400 个字符,前 10 个字符是换行符,你只想有 10 个换行符,以防 textarea 缩小到 1 个字符的列宽?限制行数而不是限制字符数仍然没有任何意义。 【参考方案1】:

自 Java 8 Update 40 以来,每个 TextInputControl 都有一个 TextFormatter 用于此任务。

它有两个功能,其中一个可用于您的任务:

可以拦截和修改用户输入的过滤器(getFilter())。这有助于将文本保持为所需的格式。

这是解决这个问题的一个非常原始的尝试:

public class Main extends Application 
    @Override
    public void start(Stage primaryStage) 
        BorderPane root = new BorderPane();

        final TextArea textArea = new TextArea();
        textArea.setTextFormatter(createTextFormatter());
        root.setCenter(textArea);

        primaryStage.setScene(new Scene(root, 400, 400));
        primaryStage.show();
    

    private static <T> TextFormatter<T> createTextFormatter() 

        final IntegerProperty lines = new SimpleIntegerProperty(1);

        return new TextFormatter<>(change -> 
            if (change.isAdded()) 
                if (change.getText().indexOf('\n') > -1) 
                    lines.set(lines.get() + 1);
                
                if (lines.get() > 10) 
                    change.setText("");
                
            
            return change;
        );
    

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

这成功地防止了用户输入超过 10 行。但是你应该改进这个解决方案,例如处理:

文字已被替换 文本已删除

TextFormatter 真的很强大,应该可以处理所有这些。

【讨论】:

我会在几个小时内调查这个问题。我相信hard(er) 部分正在计算由于文本在字段中换行而不是用户按下回车键的行数。我现在不在我的电脑附近,但我已经接近通过使用文本节点来解决这个问题了。 @Tommo 但是现在您完全改变了问题的范围......从“我如何(哪些方法,类文件)我可以限制 TextField 中的行数”到“如何确定数量TextField 中的行数".. 嗯,他们是齐头并进的,不是吗?确定行数几乎是能够限制行数的要求。 这取决于几件事。所以不一定,不。例如。我们从“行数”(这通常意味着由换行符分隔的字符串)变成了换行数.. 问题的第一行确实说明是换行还是按下了换行符。【参考方案2】:

通过以下方式分配 TextFormatter:

setTextFormatter(new TextFormatter<>(change -> 
  if(change.isContentChange()) 
    if(getWrappedLines(change.getControlText(), change.getControlNewText()) > maxRows) 
      change.setText("");
    
  
  return change;
));

还有 getWrappedLines 方法:

int getWrappedLines(String oldText, String newText) 
  Text helper = (Text)lookup(".text");
  if(helper != null) 
    helper.setText(newText);
    FontMetrics fontMetrics = Toolkit.getToolkit().getFontLoader().getFontMetrics(getFont());
    int preferredHeight = new Double(helper.getLayoutBounds().getHeight()).intValue();
    int lineHeight = new Double(fontMetrics.getLineHeight()).intValue();
    // Initially a line's preferredHeight = 14, however each new line seems   to increase the preferredHeight by
    // 16 instead of 14.
    preferredHeight = preferredHeight == lineHeight ? preferredHeight : preferredHeight - 2;
    helper.setText(oldText);
    return preferredHeight / lineHeight;
  
  else 
    return 0;
  

【讨论】:

只是从这个页面复制/粘贴在一起,没有研究,不是你的解决方案。 建议使用 TextFormatter 是朝着正确方向迈出的一步,但是 getWrappedLines 方法是我最初发布的。将两者结合起来解决了这个问题。 我完全同意。我只是想我会发布似乎对我有用的东西,以防其他人遇到类似问题或更好的建议解决方案。【参考方案3】:

简单的解决方案(未优化,仅在文本不太长时使用):

  int maxRowCount = 3;
  new TextArea().setTextFormatter (new TextFormatter<> (change -> 
    if (change.isContentChange ()) 
      if (change.getControlNewText ().chars ().filter (a -> a == '\n').count () > maxRowCount - 1) 
        change.setText ("");
      
    
    return change;
  ));

【讨论】:

以上是关于JavaFX - 限制 TextArea 行?的主要内容,如果未能解决你的问题,请参考以下文章

JavaFX:如何滚动到textarea中的特定行

将命令行文本输出到 Javafx Textarea

Javafx 8 替换 textarea 中的文本并保持格式

JavaFX:在进入 TextArea 时将插入符号/光标放在 TextArea 的末尾

JavaFX - TextArea 的掩码文本

带滚动条的只读 TextArea [JavaFx]