JavaFXTextArea固定内容行数

JavaFXTextArea固定内容行数,java,javafx,Java,Javafx,我有一个50行的固定文本区。如果内容达到第50行,则应删除第1行,并添加第51行,以保持固定的行数 此行为与应用程序控制台相同,后者在某一点之后隐藏以前的输入 目前,我正在清除文本区后,达到第50行使用计数器 public static void updateTextAreaTest(String text) { lineCount++; Platform.runLater(() -> { if (lineCount <= 50) {

我有一个50行的固定文本区。如果内容达到第50行,则应删除第1行,并添加第51行,以保持固定的行数

此行为与应用程序控制台相同,后者在某一点之后隐藏以前的输入

目前,我正在清除文本区后,达到第50行使用计数器

public static void updateTextAreaTest(String text) {
    lineCount++;

    Platform.runLater(() -> {
        if (lineCount <= 50) {
            txtAreaTest.appendText(text + "\n");
        } else {
            txtAreaTest.setText("");
            lineCount = 0;
        }
    });
}
我需要在添加新行时隐藏第一行,而不影响应用程序的性能,因为应用程序运行的线程太多

编辑:
文本区域不可编辑。TextArea将自动更新,无需用户交互。

正如评论中所建议的,ListView可能是首选选项

但是,如果要使用文本区域,可以通过在文本区域上设置a来实现。TextFormatter的过滤器可以检查文本区域的建议新文本中的行数,如果包含的行数超过允许的行数,请修改更改以删除第一行。请注意,此解决方案允许在单个操作中插入多行文本

import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javafx.animation.Animation;
import javafx.animation.KeyFrame;
import javafx.animation.Timeline;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.TextArea;
import javafx.scene.control.TextFormatter;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;
import javafx.util.Duration;


/**
 * JavaFX App
 */
public class App extends Application {

    private int lineNumber  ;
    private final int MAX_LINES = 50 ;

    private TextArea createConsole() {
        TextArea appConsole = new TextArea();
        appConsole.setWrapText(false);
        appConsole.setEditable(false);

        Pattern newline = Pattern.compile("\n");
        appConsole.setTextFormatter(new TextFormatter<String>(change ->  {

            String newText = change.getControlNewText();

            // count lines in proposed new text:
            Matcher matcher = newline.matcher(newText);
            int lines = 1 ;
            while (matcher.find()) lines++;

            // if there aren't too many lines just return the changed unmodified:
            if (lines <= MAX_LINES) return change ;

            // drop first (lines - 50) lines and replace all text
            // (there's no other way AFAIK to drop text at the beginning 
            // and replace it at the end):
            int linesToDrop = lines - MAX_LINES ;
            int index = 0 ; 
            for (int i = 0 ; i < linesToDrop ; i++) {
                index = newText.indexOf('\n', index) ;
            }
            change.setRange(0, change.getControlText().length());
            change.setText(newText.substring(index+1));

            return change  ;
        }));

        return appConsole;
    }

    @Override
    public void start(Stage stage) {

        TextArea appConsole = createConsole();

        // Fill with 45 lines to start:
        appConsole.appendText("Line 1");
        for (lineNumber = 2 ; lineNumber <= 45 ; lineNumber++) {
            appConsole.appendText("\nLine "+lineNumber);
        }

        // add a new line every 2 seconds:
        Timeline demo = new Timeline(
            new KeyFrame(Duration.seconds(2), 
                e -> appConsole.appendText("\nLine "+(lineNumber++))
            )
        );
        demo.setCycleCount(Animation.INDEFINITE);
        demo.play();

        stage.setScene(new Scene(new BorderPane(appConsole)));

        stage.show();
    }


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

}

这个解决方案的一个优点是,它是一个文本区域的fire-and-forget配置。创建文本区域,在其上设置格式设置程序,这会自动提供从不超过50行文本的功能,如果需要,可以删除开头的行,然后代码的其余部分可以根据需要调用TextArea方法,如appendText。

,如注释中所建议,对此,ListView可能是首选选项

但是,如果要使用文本区域,可以通过在文本区域上设置a来实现。TextFormatter的过滤器可以检查文本区域的建议新文本中的行数,如果包含的行数超过允许的行数,请修改更改以删除第一行。请注意,此解决方案允许在单个操作中插入多行文本

import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javafx.animation.Animation;
import javafx.animation.KeyFrame;
import javafx.animation.Timeline;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.TextArea;
import javafx.scene.control.TextFormatter;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;
import javafx.util.Duration;


/**
 * JavaFX App
 */
public class App extends Application {

    private int lineNumber  ;
    private final int MAX_LINES = 50 ;

    private TextArea createConsole() {
        TextArea appConsole = new TextArea();
        appConsole.setWrapText(false);
        appConsole.setEditable(false);

        Pattern newline = Pattern.compile("\n");
        appConsole.setTextFormatter(new TextFormatter<String>(change ->  {

            String newText = change.getControlNewText();

            // count lines in proposed new text:
            Matcher matcher = newline.matcher(newText);
            int lines = 1 ;
            while (matcher.find()) lines++;

            // if there aren't too many lines just return the changed unmodified:
            if (lines <= MAX_LINES) return change ;

            // drop first (lines - 50) lines and replace all text
            // (there's no other way AFAIK to drop text at the beginning 
            // and replace it at the end):
            int linesToDrop = lines - MAX_LINES ;
            int index = 0 ; 
            for (int i = 0 ; i < linesToDrop ; i++) {
                index = newText.indexOf('\n', index) ;
            }
            change.setRange(0, change.getControlText().length());
            change.setText(newText.substring(index+1));

            return change  ;
        }));

        return appConsole;
    }

    @Override
    public void start(Stage stage) {

        TextArea appConsole = createConsole();

        // Fill with 45 lines to start:
        appConsole.appendText("Line 1");
        for (lineNumber = 2 ; lineNumber <= 45 ; lineNumber++) {
            appConsole.appendText("\nLine "+lineNumber);
        }

        // add a new line every 2 seconds:
        Timeline demo = new Timeline(
            new KeyFrame(Duration.seconds(2), 
                e -> appConsole.appendText("\nLine "+(lineNumber++))
            )
        );
        demo.setCycleCount(Animation.INDEFINITE);
        demo.play();

        stage.setScene(new Scene(new BorderPane(appConsole)));

        stage.show();
    }


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

}

这个解决方案的一个优点是,它是一个文本区域的fire-and-forget配置。创建文本区域,在其上设置格式化程序,这会自动提供从不超过50行文本的功能,如果需要,可以删除开头的行,然后代码的其余部分可以根据需要调用TextArea方法,如appendText。

这只是通过编程方式更新的吗,或者用户正在编辑文本?如果用户正在编辑,如果他们输入的文本不在现有文本的末尾,您希望发生什么?如果有50行,他们在开始时输入了新行怎么办?@James_D no,文本区域不可编辑。没有与用户交互。您希望旧的行消失还是只是滚动到视图之外?如果是前者,那么您可能需要考虑使用ListVIEW,其中每个元素都是一行文本。@慢,我想删除旧行,如果我保留旧行,它会占用太多内存和性能问题,这就是为什么我在考虑这种方法。我期待类似于eclipse控制台或命令行的东西,它有固定的内容行数。那么ListView应该使这更容易实现。添加元素(即文本行)时,请检查列表的大小,如果达到阈值,请从列表的开头删除元素。事实上,使用ListView,您可能可以在内存中保留数千行,而不会有任何问题,因为它是一个虚拟化控件。这只是以编程方式更新的,还是用户正在编辑文本?如果用户正在编辑,如果他们输入的文本不在现有文本的末尾,您希望发生什么?如果有50行,他们在开始时输入了新行怎么办?@James_D no,文本区域不可编辑。没有与用户交互。您希望旧的行消失还是只是滚动到视图之外?如果是前者,那么您可能需要考虑使用ListVIEW,其中每个元素都是一行文本。@慢,我想删除旧行,如果我保留旧行,它会占用太多内存和性能问题,这就是为什么我在考虑这种方法。我期待类似于eclipse控制台或命令行的东西,它有固定的内容行数。那么ListView应该使这更容易实现。添加元素(即文本行)时,请检查列表的大小,如果达到阈值,请从列表的开头删除元素。事实上,使用ListView,您可能可以毫无问题地在内存中保留数千行,因为它是一个虚拟化控件。谢谢,这就是我正在寻找的,对于限制为1000或10000行的大型应用程序,这是最佳解决方案吗?有没有性能问题的缺点?计算行数是在行数上,但是使用正则表达式应该非常快,你不应该注意到。除非代码尝试添加大量行,否则找到子字符串的位置将非常快。这应该是很容易适应这个演示任何数量的l
ines进行压力测试。谢谢,这是我一直在寻找的,对于限制为1000或10000行的大规模应用来说,这是最佳解决方案吗?有没有性能问题的缺点?计算行数是在行数上,但是使用正则表达式应该非常快,你不应该注意到。除非代码尝试添加大量行,否则找到子字符串的位置将非常快。将此演示适应任意数量的行以进行压力测试应该是非常容易的。