0

我们正在尝试计算 TextArea 中的行数
以下是 TextArea 属性 PrefWidth 600 和 PrefHeight 620,MaxHeight 620
Wrap Text 设置为 true。我们正在使用带有 Scene Builder 的 JavaFX 8
我们有一个 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();
    }     
    });     
} 

请参阅代码中的注释,因为此方法管理其他任务。

4

3 回答 3

4

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

查看公共 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());

}
于 2019-10-03T13:27:17.767 回答
2

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 来获得更真实的字符数?

于 2019-10-03T05:02:37.343 回答
2

一个最小的、可重现的示例是可以复制和运行而无需太多更改的东西,也应该有自我解释的变量。

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

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
    }
}
于 2019-10-01T01:02:55.597 回答