Как ограничить количество строк в JTextArea?

Я пытаюсь сделать GUI для службы, в которой есть JTextArea для просмотра сообщений, каждое сообщение написано на одной строке и при необходимости завернуто в Word.

сообщения поступают через сокет, поэтому это просто an .добавьте (сообщение), которое я использую для обновления JTextArea, мне нужно ограничить эти строки 50 или 100, и мне не нужно ограничивать количество символов в каждой строке.

Если есть метод ограничения числовых строк в JTextArea или если есть альтернативный способ сделать это?

Я мог бы реально использовать помощь в этом вопросе.

редактировать

проблема в том, что каждый клиент может отправлять бесконечные строки, Все эти строки должны быть читаемыми, поэтому это не простая проверка количества строк в JTextArea. Мне нужно удалить старые строки, чтобы просмотреть новые строки.

4 ответов


будет ли это более эффективно?

final int SCROLL_BUFFER_SIZE = 100;
public void trunkTextArea(JTextArea txtWin)
{
    int numLinesToTrunk = txtWin.getLineCount() - SCROLL_BUFFER_SIZE;
    if(numLinesToTrunk > 0)
    {
        try
        {
            int posOfLastLineToTrunk = txtWin.getLineEndOffset(numLinesToTrunk - 1);
            txtWin.replaceRange("",0,posOfLastLineToTrunk);
        }
        catch (BadLocationException ex) {
            ex.printStackTrace();
        }
    }
}

использовать этой получить строку и столбец

добавьте DocumentFilter, который проверяет количество строк (передайте doc.getlength () offset) и предотвратить добавление большего количества текста.

или вы можете создать фиктивный невидимый JTextArea и добавить туда весь текст. Затем измерьте последнюю разрешенную строку и вырежьте текст.


Ниже приведен грубый DocumentFilter, который, похоже, работает. Его основной подход заключается в том, чтобы позволить вставить/добавить, запросить количество строк после факта, если больше max, удалите строки с самого начала.

остерегайтесь: строки, подсчитанные с помощью методов textArea, являются (скорее всего, ждут подтверждения от @Stani) строками между-cr, а не фактическими строками как layouted. В зависимости от вашего точного требования, они могут или не могут установить вас (если нет, используйте Stan utility methods)

Я был удивлен и не совсем уверен, что это безопасно

  • surprised: метод insert не вызывается, необходим для реализации метода replace (в производственном готовом коде, вероятно, оба)
  • не уверен, что textArea гарантированно возвращает обновленные значения в методах фильтра (вероятно, нет, тогда проверка длины может быть завернута в invokeLater)

код:

public class MyDocumentFilter extends DocumentFilter {

    private JTextArea area;
    private int max;

    public MyDocumentFilter(JTextArea area, int max) {
        this.area = area;
        this.max = max;
    }

    @Override
    public void replace(FilterBypass fb, int offset, int length,
            String text, AttributeSet attrs) throws BadLocationException {
        super.replace(fb, offset, length, text, attrs);
        int lines = area.getLineCount();
        if (lines > max) {
            int linesToRemove = lines - max -1;
            int lengthToRemove = area.getLineStartOffset(linesToRemove);
            remove(fb, 0, lengthToRemove);
        }
    }
}

// usage
JTextArea area = new JTextArea(10, 10);
((AbstractDocument) area.getDocument()).setDocumentFilter(new MyDocumentFilter(area, 3));

мой подход работает с содержимым JTextPane в качестве документа. Предполагается, что ваша программа добавляла текст в конец документа снова и снова, так что при вызове doc.getCharacterElement (1), вы получите в основном элемент leaf, который представляет самую раннюю строку кода. Это то, что мы хотим удалить, поэтому мы получаем начальные и конечные смещения этого элемента и вызываем метод remove, чтобы вырезать самый ранний текст.

Это может быть выборочно выполняется путем проверки того, превышает ли общее количество символов миллион (как я сделал ниже), или на основе количества строк, которые вы уже добавили.

Если вы хотите основывать его на количестве уже добавленных строк, вам понадобится поле, которое увеличивается каждый раз, когда вы печатаете в JTextPane, так что этот код запускается один раз каждый раз, когда вы печатаете новую строку текста, и количество превышает ваше максимальное значение.

        JTextPane pane = ...
        StyledDocument doc = pane.getStyledDocument();
        int size = doc.getLength();
        if (size > 1000000) {
            out.println("Size: " + size);
            out.println(":" + 1);
            int i = 0;
            Element e = doc.getCharacterElement(i + 1);
            int start = e.getStartOffset();
            int end = e.getEndOffset();

            try {
                doc.remove(start, end);
            } catch (BadLocationException e1) {
                // TODO Auto-generated catch block
                e1.printStackTrace();
            }
        }

Ура!