JavaFX: как перейти к определенной строке в текстовой области - PullRequest
0 голосов
/ 01 июля 2018
package sample;

import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.TextArea;
import javafx.stage.Stage;
import java.util.stream.IntStream;

public class Main extends Application {

@Override
public void start(Stage primaryStage) throws Exception{
    final StringBuilder sb = new StringBuilder();
    IntStream.range(1, 100).forEach(i -> sb.append("Line " + i + "\n"));

    TextArea ta = new TextArea();
    ta.setText(sb.toString());

    //how to I get line 30 at top of the visible textarea
    double someValue = 0;
    ta.setScrollTop(someValue);

    primaryStage.setTitle("Hello World");
    primaryStage.setScene(new Scene(ta, 300, 300));
    primaryStage.show();
}

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

}

Как получить строку 30 в верхней части видимой области текста? Я думаю, что 'someValue' должно быть относительно общей высоты, которую можно прокрутить Но какова общая высота, которую можно прокрутить

Вот результат, которого я хочу достичь:
This is the result I want to achieve

1 Ответ

0 голосов
/ 02 июля 2018

Это немного сложно. Мы могли бы просто определить высоту каждой строки и вызвать ta.setScrollTop((line - 1) * lineHeight);, но мы не знаем, какой межстрочный интервал TextArea использует.

Но я обнаружил, что TextAreaSkin содержит публичные методы определения границ для любого выбранного символа, нам просто нужно знать его индекс.

@Override
public void start(Stage primaryStage) throws Exception{
    final StringBuilder sb = new StringBuilder();
    IntStream.range(1, 100).forEach(i -> sb.append("Line " + i + "\n"));

    TextArea ta = new TextArea();
    ta.setText(sb.toString());

    // TextArea did not setup its skin yet, so we can't use it right now.
    // We just append our task to the user tasks queue.
    Platform.runLater(() -> {

        // Define desired line
        final int line = 30;

        // Index of the first character in line that we look for.
        int index = 0;
        // for this example following line will work:
        // int index = ta.getText().indexOf("Line " + line);

        // for lines that do not contain its index we rely on "\n" count
        int linesEncountered = 0;
        boolean lineFound = false;
        for (int i = 0; i < ta.getText().length(); i++) {
            // count characters on our way to our desired line
            index++;

            if(ta.getText().charAt(i) == '\n') {
                // next line char encountered
                linesEncountered++;
                if(linesEncountered == line-1) {
                    // next line is what we're looking for, stop now
                    lineFound = true;
                    break;
                }
            }
        }

        // scroll only if line found
        if(lineFound) {
            // Get bounds of the first character in the line using internal API (see comment below the code)
            Rectangle2D lineBounds = ((com.sun.javafx.scene.control.skin.TextAreaSkin) ta.getSkin()).getCharacterBounds(index);

            // Scroll to the top-Y of our line
            ta.setScrollTop(lineBounds.getMinY());
        }
    });

    primaryStage.setTitle("Hello World");
    primaryStage.setScene(new Scene(ta, 300, 300));
    primaryStage.show();
}

Это решение работает на Java 8, на 9+ TextAreaSkin было перемещено в общедоступный пакет, поэтому все, что вам нужно для его работы, это заменить com.sun.javafx.scene.control.skin.TextAreaSkin на javafx.scene.control.skin.TextAreaSkin

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...