“textarea”中的 JavaFX 8 计数行

Posted

技术标签:

【中文标题】“textarea”中的 JavaFX 8 计数行【英文标题】:JavaFX 8 count rows in "textarea" 【发布时间】:2020-01-30 03:45:29 【问题描述】:

我们正在尝试计算 TextArea 中的行数 这是 TextArea 属性 PrefWidth 600 和 PrefHeight 620 和 MaxHeight 620 Wrap Text 设置为 true。我们将 JavaFX 8 与 Scene Builder 一起使用 我们有一个 textPropertyListiner,它会在 TextArea.getLength 大于某个值时触发警报 此方法的问题是它不考虑用户输入回车 \n

所以我们实现了这段代码来捕获\n

    String toCount = txaDiaryEntry.getText();
    String [] lineArray = toCount.split("\n");
    int LA = lineArray.length - 1;

    if(LA == 0)
      rc = rc - 1;
      System.out.println("###### LA "+LA+" RC "+rc);
    

if 测试始终为零,因此每次用户在输入一个回车后键入任何内容时都会运行此测试 此代码在 textPropertyListiner 内 当输入的文本进行换行时,不会创建 \n 我们查看了许多旧帖子并尝试了一些没有结果的示例问题是如何计算具有回车符和换行符的 TextArea 中的行数为真? 在我进行测试时,我注意到发布代码的一些问题是 LA 值继续增加。因为我们很少使用 Array 我的猜测是当值达到 1 时需要清除 Array 因此,如果有人愿意解释如何使用此 String[] 数组来完成此操作,我们将对其进行测试

我们已经编辑了问题代码,以反映计算两个换行和当用户按下 ENTER 键时的工作示例。虽然这可行,但我们可能会补充一点,使用行计数来防止进一步的文本输入不如计算 TextArea 中的字符数有利。

@Override
public void initialize(URL url, ResourceBundle rb) 
txtTitle.setStyle("-fx-text-fill: black;");
getDate();

    if(doEDIT.equals("TRUE"))
       btnEdit.setVisible(true);
       btnSave.setVisible(false);
        try 
            ReadChildTable();
         catch (SQLException ex) 
            Logger.getLogger(EnterController.class.getName()).log(Level.SEVERE, null, ex);
        
    

    try 
        ReadParent();
     catch (SQLException | IOException ex) 
        Logger.getLogger(EnterController.class.getName()).log(Level.SEVERE, null, ex);
    

    txaDiaryEntry.textProperty().addListener((observable, oldValue, newValue) -> 

    EC = txaDiaryEntry.getLength();
    tEC = tEC + 1;
    // this counts line wraps every 62 char
    if(tEC == 62)
        RC = RC - 1;
        tEC = 0;
    

    // This counts ENTER key presses
    String toCount = txaDiaryEntry.getText();
    String [] lineArray = toCount.split("\n");
    LA = lineArray.length - 1;

    if(LA == tLA)
        tLA = LA + 1;
        RC = RC - 1;
    else if(tLA < LA)
            tLA = LA + 1;
             RC = RC - (LA - 1);
    else  
    

    // This test counter
    int minus = EC+(LA * 40);
    int val = 1200 - minus ;
    txtCR.setText(String.valueOf(val));
    uEC = uEC - val;

    if(LA == 0)
       uEC = 1200;
    else
       uEC = 960;// 880
    

    if(EC > uEC)
    //if(RC == 0)  
        alertTYPE = "4";
        //RC = RC + 1;
        try 
            customAlert();
         catch (IOException ex) 
            Logger.getLogger(EnterController.class.getName()).log(Level.SEVERE, null, ex);
        
        txaDiaryEntry.requestFocus();
         
    );     
 

请查看代码中的 cmets,因为此方法管理其他任务。

【问题讨论】:

可能我有点困惑..您是否希望输入文本中的行数(即由\n分隔)或可见行/行数在textarea中使用(因为 textwrap 和 \n)? @SaiDandem 我们想要捕获用户按下 ENTER 时创建的 \n 的数量,并从预设的 RowCount 中减去我们可以计算用户只是键入时创建的行数 Issue is not able重置或清除字符串[],如我对问题的编辑中所述,它不断增加 @SaiDandem 我们尝试了这段代码但没有运气 lineArray = null 不确定到底是什么问题。因为对我来说,添加这段代码给了我正确的行数。可能你能提供一个Minimal, Reproducible Example textArea.textProperty().addListener((obs,old,txt)-> System.out.println(txt.split("\n").length); ); 您的要求并不完全清楚。你想计算有多少文字行分隔符,文本在屏幕上被换行多少次,还是两者兼而有之?请注意,文本换行纯粹是一种渲染“技巧”,不会导致在文本中插入行分隔符。您必须根据字符的宽度和换行宽度计算一行文本的换行次数。问题在于 JavaFX 没有提供公共 API 来根据字体测试字符的宽度——至少在 JavaFX 13 中没有。 【参考方案1】:

正如@Slaw 在他的一个 cmets 中已经指出的那样,没有 public API 可以访问 textArea 中的行数(我强调)。另一方面,有内部 API 可以提供我们需要的东西 - 如果我们足够大胆并允许使用内部组件。

查看public api并深入研究TextAreaSkin的实现细节,结果是(目前最高到fx13,可能更晚)

textArea.getParagraphs() 似乎返回了由硬换行符分隔的字符序列 皮肤将所有段落合并到一个文本节点中 text has-一个处理行/字符布局的textLayout字段 textLayout 提供了一个方法getLines(),它返回一个由软换行符或硬换行符分隔的 textLines 数组,为了计算我们只对它的长度感兴趣。

下面是一个快速示例,演示如何使用这些内部结构。基本上,它查找区域的文本节点(附加皮肤后可用),反射性地访问其 textLayout 并查询行数组的长度。

请注意,这是针对 fx9+ 的(除了将皮肤拉入公共范围之外,可能对 fx8 没有太大变化,不过没有检查)。为了允许访问内部,我们需要在编译时和运行时调整模块访问限制。

编译时间:

--add-exports javafx.graphics/com.sun.javafx.scene.text=ALL_UNNAMED

运行时:

--add-opens javafx.graphics/com.sun.javafx.scene.text=ALL-UNNAMED
--add-opens javafx.graphics/javafx.scene.text=ALL-UNNAMED

示例:

public class TextAreaLineCount extends Application 

    String info = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. " +
            "Nam tortor felis, pulvinar in scelerisque cursus, pulvinar at ante. " +
            "Nulla consequat congue lectus in sodales.";

    private Parent createContent() 
        TextArea area = new TextArea(info);
        area.setWrapText(true);

        area.appendText("\n" + info);

        Button append = new Button("append paragraph");
        append.setOnAction(e -> 
            area.appendText("\n " + info);
            LOG.info("paragraphs: " + area.getParagraphs().size());
        );
        Button logLines = new Button("log lines");
        logLines.setOnAction(e -> 
            Text text = (Text) area.lookup(".text");
            // getTextLayout is a private method in text, have to access reflectively
            // this is my utility method, use your own :)
            TextLayout layout = (TextLayout) FXUtils.invokeGetMethodValue(Text.class, text, "getTextLayout");
            LOG.info("" + layout.getLines().length);
        );
        BorderPane content = new BorderPane(area);
        content.setBottom(new HBox(10, append, logLines));
        return content;
    

    @Override
    public void start(Stage stage) throws Exception 
        stage.setScene(new Scene(createContent()));
        stage.setTitle(FXUtils.version());
        stage.show();
    

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

    @SuppressWarnings("unused")
    private static final Logger LOG = Logger
            .getLogger(TextAreaLineCount.class.getName());


【讨论】:

叫出城外。 ReadParent 是一种从未连接到 txaDiaryEntry.textProperty().addListener 的数据库中读取的方法,当用户将数据输入到 txaDiaryEntery TextArea 时,我们试图仅捕获一个 \n 和多个 \n 以减少 RowCount (RC)跨度> 【参考方案2】:

Minimal, Reproducible Example 是可以复制和运行而无需太多更改的东西,也应该有自我解释的变量。

供您参考,我提供了一个演示,您能否根据您的要求对其进行更新。由于变量无法解释,因此很难遵循您的代码。

import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.control.TextArea;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.Priority;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;

public class TextAreaLinesCount_Demo extends Application 
    @Override
    public void start(Stage stage) throws Exception 
        final VBox root = new VBox();
        root.setSpacing(10);
        root.setPadding(new Insets(10));
        final Scene sc = new Scene(root, 350, 200);
        stage.setScene(sc);
        stage.show();

        Label lines = new Label();
        Label alert = new Label();
        GridPane gp = new GridPane();
        gp.setHgap(10);
        gp.setVgap(10);
        gp.addRow(0, new Label("No of Lines:"), lines);
        gp.addRow(1, new Label("Alert:"), alert);

        TextArea textArea = new TextArea();
        textArea.setWrapText(true);
        textArea.textProperty().addListener((obs, old, text) -> 
            lines.setText(text.split("\n").length + "");
            validate(text, alert);
        );
        VBox.setVgrow(textArea, Priority.ALWAYS);
        root.getChildren().addAll(gp, textArea);

        textArea.setText("Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.");
    

    private void validate(String text, Label alert) 
        // Can you add your logic here.. and update the "alert" label for when to show the alert
    

【讨论】:

请学习 java 命名约定并遵守它们(口齿伶俐 【参考方案3】:

Grendel 这段代码似乎使使用 String[ ] 数组计算 \n 的任务变得复杂。这段代码贴在下面

    // This counts ENTER key presses
String toCount = txaDiaryEntry.getText();
String [] lineArray = toCount.split("\n");
LA = lineArray.length - 1;

if(LA == tLA)
    tLA = LA + 1;
    RC = RC - 1;
else if(tLA < LA)
        tLA = LA + 1;
         RC = RC - 1;
else  

因此,这里不是处理 String [ ] 数组,而是只计算 \n 出现次数的代码少一点,并且正如您的原始代码所做的那样,它减去给定数量的字符

    String toCount = txaDiaryEntry.getText();
    S = toCount.split("\n",-1).length - 1;
    RowCount = RowCount - 1;    
    // This test counter
    int minus = EC+(S * 40);
    int val = 1200 - minus ;

处理 String [ ] 数组的所有代码都很聪明,但非常疯狂且难以理解。现在您可以使用数字 40 来获得更真实的字符数?

【讨论】:

不,他不是。自动换行模式下的 textarea 不会在数据中插入任何中断,这些“软换行”仅存在于其内部表示中。所以我们需要一个肮脏的黑客,因为 javaFX 不允许我们这样做。又一个接受过度乐观的 hellowording 框架......

以上是关于“textarea”中的 JavaFX 8 计数行的主要内容,如果未能解决你的问题,请参考以下文章

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

JavaFX - 限制 TextArea 行?

javafx 8在textarea中编辑文本

将命令行文本输出到 Javafx Textarea

如何禁用 TextArea (JavaFX) 中的文本选择?

JavaFX TextArea 中的 Tab 键导航