JavaFX - 自动化 Textarea 清除(滚动策略?)
JavaFX - Automate Textarea purging (rolling policy?)
我有一个 Textarea 组件,用于显示 2 个应用程序之间的消息(确切地说是 HL7 消息)。每次成功处理一条消息时,都会记录该消息以及从接收系统发回的确认信息。这些消息可以成千上万发送,我觉得当这些组件 "overflows" 时,不可避免地会出现问题。我想实施一个翻转策略,有点像 log4j,你可以告诉它只保留 10 个 1MB 的文件。我希望有一个用户可以设置的值,并且我的组件(可能是 Textarea 组件的扩展)将自动仅保留该行数并在添加新行时清除第一行。我是 JavaFX 的新手(来自 Swing),我查看了这些选项,但不太明白如何做到这一点。
谢谢
正如我在问题的评论部分中提到的,我建议您使用 ListView
而不是 TextArea
。这会给您带来一些好处:
ListView
是一个 "virtual" 控件——它只呈现足够的 cells 来填充可见的 space 并且在滚动时重复使用单元格。这允许一个人在 ListView
中拥有数千个项目而不会影响性能。
ListView
的模型是 an observable list,这是一种比在 [=12] 中有一个巨型 String
更好的表示单独消息的方式=].当向列表中添加一个元素导致它超出某个任意容量时,您可以简单地从所述列表的开头删除一个项目(或者结束,如果在顶部而不是底部插入项目)。
A ListView
在显示消息时提供了更大的灵活性。这是通过自定义 cell factory. For instance, you could have certain ranges of the message be different colors by using a TextFlow
as the graphic of the ListCell
. Make sure you read the documentation of Cell.updateItem(Object,boolean)
实现的,但是,您必须正确地覆盖该方法;不这样做可能会导致伪影,因为单元会被重复使用。
一个简单的例子:
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Consumer;
import javafx.animation.PauseTransition;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.ListView;
import javafx.stage.Stage;
import javafx.util.Duration;
public class Main extends Application {
private static void generateMessages(Consumer<String> onNewMessage) {
AtomicInteger counter = new AtomicInteger();
PauseTransition pt = new PauseTransition(Duration.seconds(1));
pt.setOnFinished(e -> {
onNewMessage.accept(String.format("Message #%,d", counter.incrementAndGet()));
pt.playFromStart();
});
pt.playFromStart();
}
@Override
public void start(Stage primaryStage) {
ListView<String> listView = new ListView<>();
primaryStage.setScene(new Scene(listView, 500, 300));
primaryStage.show();
generateMessages(message -> {
listView.getItems().add(message);
if (listView.getItems().size() > 10) {
listView.getItems().remove(0);
}
});
}
}
我比接受的答案更进一步(没有它我仍然会尝试使用 TextArea!)并构建了这个自定义组件(是的,有一个空的 catch 块,但我有一个清晰的日志按钮,它抛出一个日志为空时异常,处理:) )
public class HL7ListView extends ListView<String>
{
private int serviceLogMaxEntries;
public HL7ListView()
{
super();
getItems().addListener((ListChangeListener<String>) listener ->
{
if (getItems().size() > serviceLogMaxEntries)
{
Platform.runLater(() ->
{
try
{
getItems().remove(0);
}
catch (Exception ex)
{}
});
}
});
}
public void setServiceLogMaxEntries(int serviceLogMaxEntries)
{
this.serviceLogMaxEntries = serviceLogMaxEntries;
}
}
我有一个 Textarea 组件,用于显示 2 个应用程序之间的消息(确切地说是 HL7 消息)。每次成功处理一条消息时,都会记录该消息以及从接收系统发回的确认信息。这些消息可以成千上万发送,我觉得当这些组件 "overflows" 时,不可避免地会出现问题。我想实施一个翻转策略,有点像 log4j,你可以告诉它只保留 10 个 1MB 的文件。我希望有一个用户可以设置的值,并且我的组件(可能是 Textarea 组件的扩展)将自动仅保留该行数并在添加新行时清除第一行。我是 JavaFX 的新手(来自 Swing),我查看了这些选项,但不太明白如何做到这一点。
谢谢
正如我在问题的评论部分中提到的,我建议您使用 ListView
而不是 TextArea
。这会给您带来一些好处:
ListView
是一个 "virtual" 控件——它只呈现足够的 cells 来填充可见的 space 并且在滚动时重复使用单元格。这允许一个人在ListView
中拥有数千个项目而不会影响性能。ListView
的模型是 an observable list,这是一种比在 [=12] 中有一个巨型String
更好的表示单独消息的方式=].当向列表中添加一个元素导致它超出某个任意容量时,您可以简单地从所述列表的开头删除一个项目(或者结束,如果在顶部而不是底部插入项目)。A
ListView
在显示消息时提供了更大的灵活性。这是通过自定义 cell factory. For instance, you could have certain ranges of the message be different colors by using aTextFlow
as the graphic of theListCell
. Make sure you read the documentation ofCell.updateItem(Object,boolean)
实现的,但是,您必须正确地覆盖该方法;不这样做可能会导致伪影,因为单元会被重复使用。
一个简单的例子:
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Consumer;
import javafx.animation.PauseTransition;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.ListView;
import javafx.stage.Stage;
import javafx.util.Duration;
public class Main extends Application {
private static void generateMessages(Consumer<String> onNewMessage) {
AtomicInteger counter = new AtomicInteger();
PauseTransition pt = new PauseTransition(Duration.seconds(1));
pt.setOnFinished(e -> {
onNewMessage.accept(String.format("Message #%,d", counter.incrementAndGet()));
pt.playFromStart();
});
pt.playFromStart();
}
@Override
public void start(Stage primaryStage) {
ListView<String> listView = new ListView<>();
primaryStage.setScene(new Scene(listView, 500, 300));
primaryStage.show();
generateMessages(message -> {
listView.getItems().add(message);
if (listView.getItems().size() > 10) {
listView.getItems().remove(0);
}
});
}
}
我比接受的答案更进一步(没有它我仍然会尝试使用 TextArea!)并构建了这个自定义组件(是的,有一个空的 catch 块,但我有一个清晰的日志按钮,它抛出一个日志为空时异常,处理:) )
public class HL7ListView extends ListView<String>
{
private int serviceLogMaxEntries;
public HL7ListView()
{
super();
getItems().addListener((ListChangeListener<String>) listener ->
{
if (getItems().size() > serviceLogMaxEntries)
{
Platform.runLater(() ->
{
try
{
getItems().remove(0);
}
catch (Exception ex)
{}
});
}
});
}
public void setServiceLogMaxEntries(int serviceLogMaxEntries)
{
this.serviceLogMaxEntries = serviceLogMaxEntries;
}
}