Textarea滚动窗格在文本追加中保留

Ree*_*nda 5 javafx javafx-2 javafx-8

这是我对textarea附加文本的测试代码,

 public class TextAreaScrollHold extends Application {

    TextArea area = new TextArea();

    @Override
    public void start(Stage primaryStage) {
        StackPane root = new StackPane();
        root.getChildren().add(area);

        Scene scene = new Scene(root, 300, 250);

        primaryStage.setTitle("Hello World!");
        primaryStage.setScene(scene);
        primaryStage.show();
        addTextInTextArea();
    }

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        launch(args);
    }

    public void addTextInTextArea() {
        for (int i = 0; i < 15; i++) {
            area.appendText("Hello World " + i + "\n");
        }

        Task<Void> task = new Task() {
            @Override
            protected Void call() throws Exception {
                for (int i = 15; i < 100; i++) {
                    area.appendText("Hello World " + i + "\n");
                    Thread.sleep(1000);
                }

                return null;
            }
        };
        new Thread(task).start();
    }

}
Run Code Online (Sandbox Code Playgroud)

它我的代码数据将在线程中更新。我需要在textarea中更新数据时如何在滚动条中按住。我参考了JavaFX TextArea和autoscroll,并可以访问TextArea的“滚动窗格”或“滚动条”,但是如何解决此问题。

我需要

  • 当textarea中的数据更新时,我将滚动该栏将保持的文本区域滚动条。

    textArea.scrollTopProperty().addListener(new ChangeListener<Number>() {
                @Override
        public void changed(ObservableValue<? extends Number> observable, Number oldValue, Number newValue) {
                        textArea.setScrollTop(100);
                }
            });
    
    Run Code Online (Sandbox Code Playgroud)

我已使用此代码,但滚动条在未移动的栏中将固定在像素100的位置

Rol*_*and 1

您可以使用getCaretPostionpostionCaret(是的,该 setter 的方法名称对于 Java 来说很尴尬)。

我很快为您起草了一些代码,使用滚动锁定按钮来启用/禁用滚动:

import javafx.application.Application;
import javafx.concurrent.Task;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.TextArea;
import javafx.scene.control.ToggleButton;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;

public class ConsoleDemo extends Application {

    Console console = new Console();

    @Override
    public void start(Stage primaryStage) {

        StackPane root = new StackPane();
        root.getChildren().add(console);

        Scene scene = new Scene(root, 300, 250);

        primaryStage.setTitle("Console Demo");
        primaryStage.setScene(scene);
        primaryStage.show();

        addTextInTextArea();
    }

    /**
     * @param args
     *            the command line arguments
     */
    public static void main(String[] args) {
        launch(args);
    }

    public void addTextInTextArea() {
        for (int i = 0; i < 15; i++) {
            console.log("Hello World " + i);
        }

        Task<Void> task = new Task() {
            @Override
            protected Void call() throws Exception {
                for (int i = 15; i < 100; i++) {
                    console.log("Hello World " + i);
                    Thread.sleep(1000);
                }

                return null;
            }
        };
        new Thread(task).start();

    }

    public class Console extends BorderPane {

        TextArea textArea = new TextArea();
        int scrollLockPos = -1;

        public Console() {

            HBox toolbar = new HBox();

            ToggleButton scrollLockButton = new ToggleButton("Scroll Lock");

            scrollLockButton.setOnAction(e -> {
                if (scrollLockButton.isSelected()) {
                    scrollLockPos = textArea.getCaretPosition();
                } else {
                    scrollLockPos = -1;
                }
            });

            HBox.setMargin(scrollLockButton, new Insets(5, 5, 5, 5));
            toolbar.getChildren().add(scrollLockButton);

            setCenter(textArea);
            setTop(toolbar);

        }

        public void log(String text) {

            textArea.appendText(text + "\n");

            if (scrollLockPos != -1) {
                textArea.positionCaret(scrollLockPos);
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

这不是最好的解决方案,但除非您想在滚动锁定时在文本区域中使用选择,否则此解决方案有效。为了获得正确的解决方案,您需要访问皮肤/滚动窗格/滚动条,并且随着即将推出的 Java 9 版本及其模块化,您不知道您将能够访问什么,因为对它们的访问当前被标记为“受限”。


编辑:

这是仅使用 Range 控制台组件的替代解决方案。在此版本中,您可以选择文本并在滚动锁定按钮按下时保持选择:

import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.control.Button;
import javafx.scene.control.IndexRange;
import javafx.scene.control.TextArea;
import javafx.scene.control.ToggleButton;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;

/**
 * Console which provides a mechanism to lock scrolling. Selecting text and copying it works while scrolling is locked.
 */
public class Console extends BorderPane {

    TextArea textArea = new TextArea();
    ToggleButton scrollLockButton;
    IndexRange range;

    public Console() {

        initComponents();

    }

    private void initComponents() {

        // toolbar
        HBox toolbar = new HBox();
        toolbar.setAlignment(Pos.CENTER_RIGHT);

        // clear
        Button clearButton = new Button("Clear");
        clearButton.setOnAction(e -> {
            textArea.clear();
        });

        // scroll lock
        scrollLockButton = new ToggleButton("Scroll Lock");

        // button positions & layout
        Insets insets = new Insets(5, 5, 5, 5);
        HBox.setMargin(clearButton, insets);
        HBox.setMargin(scrollLockButton, insets);

        toolbar.getChildren().addAll(clearButton,scrollLockButton);

        // component layout
        setCenter(textArea);
        setTop(toolbar);

    }


    public void log(String text) {

        if (scrollLockButton.isSelected()) {
            range = textArea.getSelection();
        }

        textArea.appendText(text + "\n");

        if (scrollLockButton.isSelected()) {
            textArea.selectRange(range.getStart(), range.getEnd());
        }
    }
}
Run Code Online (Sandbox Code Playgroud)