Как использовать Caret, чтобы узнать, в какой строке он находится из JTextPane? (Джава)

Проблема: у меня есть CaretListener и DocumentListener, прослушивающие JTextPane.

Мне нужен алгоритм, который может определить, в какой строке находится курсор в JTextPane, вот наглядный пример:

альтернативный текст

Результат: 3-я строка

альтернативный текст

Результат: 2-я строка

альтернативный текст

Результат: 4-я строка

и если алгоритм может сказать, какая строка вставки находится в JTextPane, должно быть довольно легко подстроить все, что находится между скобками, как изображение (вставка находится в символе m из metadata):

альтернативный текст

--

Вот как я делю весь текст, полученный из JTextPane, на предложения:

String[] lines = textPane.getText().split("\r?\n|\r", -1);

Предложения в textPane разделяются \n.

Проблема в том, как я могу манипулировать курсором, чтобы сообщить мне, в какой позиции и в какой строке он находится? Я знаю, что точка вставки указывает, в какой позиции она находится, но я не могу сказать, в какой строке она находится. Предполагая, что если я знаю, в какой строке находится курсор, я могу просто сделать lines[<line number>] и манипулировать строкой оттуда.

Вкратце: как использовать CaretListener и/или DocumentListener, чтобы узнать, на какой строке в данный момент находится курсор, и извлечь строку для дальнейшей строки манипуляция? Пожалуйста помоги. Спасибо.

Дайте мне знать, если необходимы дальнейшие разъяснения. Спасибо за ваше время.


person Alex Cheng    schedule 01.05.2010    source источник


Ответы (3)


Вот запрошенный вами исходный код:

static int getLineOfOffset(JTextComponent comp, int offset) throws BadLocationException {
    Document doc = comp.getDocument();
    if (offset < 0) {
        throw new BadLocationException("Can't translate offset to line", -1);
    } else if (offset > doc.getLength()) {
        throw new BadLocationException("Can't translate offset to line", doc.getLength() + 1);
    } else {
        Element map = doc.getDefaultRootElement();
        return map.getElementIndex(offset);
    }
}

static int getLineStartOffset(JTextComponent comp, int line) throws BadLocationException {
    Element map = comp.getDocument().getDefaultRootElement();
    if (line < 0) {
        throw new BadLocationException("Negative line", -1);
    } else if (line >= map.getElementCount()) {
        throw new BadLocationException("No such line", comp.getDocument().getLength() + 1);
    } else {
        Element lineElem = map.getElement(line);
        return lineElem.getStartOffset();
    }
}

...

public void caretUpdate(CaretEvent e) {
    int dot = e.getDot();
    int line = getLineOfOffset(textComponent, dot);
    int positionInLine = dot - getLineStartOffset(textComponent, line);
    ...
}
person user57697    schedule 01.05.2010
comment
@joppux: Вау, спасибо! Не могли бы вы объяснить немного вашего кода? - person Alex Cheng; 01.05.2010
comment
Модель документа текстового компонента (подкласс Document) состоит из элементов (класс javax.swing.text.Element). Для большинства документов элементы — это строки текста, поэтому работа с элементами — это работа со строками. Большая часть кода просто проверяет неправильные аргументы, а остальное просто. - person user57697; 01.05.2010
comment
Ну, я посмотрел в документах, так что кажется, что это работает только для PlainDocument, более сложные документы (такие как DefaultStyledDocument или HTMLDocument) требуют более сложного кода. - person user57697; 01.05.2010
comment
@joppux: А? Я использую экземпляр StyledDocument для AbstractDocument, и это сработало. Хм. - person Alex Cheng; 01.05.2010

Используйте понятие абзаца в StyledDocument с JTextPane.getStyledDocument.

По положению курсора вы знаете текущий абзац с помощью StyledDocument.getParagraph(pos). Затем вы перебираете абзацы из StyledDocument.getRootElements и дочерних элементов, чтобы найти номер текущего абзаца, то есть номер текущей строки.

Извините за мой английский.

person Istao    schedule 01.05.2010
comment
@Istao: Все в порядке, спасибо за попытку ответить. Английский тоже не мой родной язык. знак равно - person Alex Cheng; 01.05.2010
comment
Я не могу найти определение абзаца. Предполагается, что это абстрактное понятие в интерфейсе StyledDocument и абстрактном классе AbstractDocument (документация которого гласит: ...Подклассы должны определять для себя, что именно представляет собой абзац....), но DefaultStyledDocument это конкретный класс. Самое близкое к определению это ... Абзац состоит как минимум из одного дочернего элемента, который обычно является листом..... AbstractDocument, похоже, гарантирует, что абзацы должны начинаться/заканчиваться только на \n, но я не могу найти никакой гарантии, что они не будут иметь встроенных \n. - person Evgeni Sergeev; 22.04.2016

Вот как я делю весь текст, полученный из JTextPane, на предложения:

Ваше решение не очень эффективно.

Прежде всего, в документе хранится только «\n», независимо от того, какая ОС используется. Таким образом, вы можете упростить регулярное выражение.

Однако нет необходимости использовать регулярное выражение для анализа всего документа, поскольку вам нужна только 1 строка в документе. Теперь, когда вы знаете об интерфейсе Element, вы можете сделать код более эффективным.

а) получить строку, как показано ранее
б) теперь вы можете получить элемент, представленный этой строкой, из корневого элемента
в) теперь вы можете использовать смещения начала/конца и метод getText(...) метод, чтобы получить только текст для этой конкретной строки.

person camickr    schedule 01.05.2010
comment
@camickr: извините, я плохо разбираюсь в Элементе, особенно в (b), на который вы указываете. Не могли бы вы пояснить, приведя пример? - person Alex Cheng; 01.05.2010
comment
Что ж, начните с чтения API. Методы смещения начала/конца находятся в классе Element, а метод getText(), как вы знаете, находится в классе Document. Что касается примера, у вас уже есть рабочий пример. joppux уже показал вам, как получить начальное смещение. Итак, еще 2 строки кода, чтобы получить конечное смещение, а затем использовать начальное и конечное смещение, извлечь текст с помощью метода getText(). Если у вас возникли проблемы, опубликуйте свой SSCCE: sscce.org. Вы узнаете больше, пробуя и делая ошибки, а не просто копируя код. Потратьте время, чтобы понять, как работает код, который вы копируете. - person camickr; 01.05.2010
comment
Ой. Я думал, как мне получить текст из Element, отсюда и вопрос. Я думаю, что правильно понял endOffset, однако использование того, что вы предложили, нарушает мою текущую реализацию. Я буду придерживаться своего старого кода, пока не выясню, что не так. В любом случае, спасибо. - person Alex Cheng; 02.05.2010