【问题标题】:JavaFX 8 count rows in "textarea"“textarea”中的 JavaFX 8 计数行
【发布时间】: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 中没有。

标签: javafx javafx-8 textarea


【解决方案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 框架......
猜你喜欢
  • 1970-01-01
  • 2020-03-16
  • 2016-12-18
  • 2015-09-20
  • 1970-01-01
  • 1970-01-01
  • 2015-04-24
  • 2020-03-23
  • 2016-10-29
相关资源
最近更新 更多