7

我正在尝试为服务制作一个 GUI,它有一个 JTextArea 来查看消息,每条消息都写在一行上,并在需要时进行自动换行。

消息通过套接字到达,因此它只是我用来更新 JTextArea 的一个 .append(message),我需要将这些行限制为 50 或 100,并且我不需要限制每行的字符数。

如果有一种方法可以限制 JTextArea 中的行数,或者是否有另一种方法?

我真的可以在这件事上使用帮助。

编辑

问题是每个客户端可以发送无限行,所有这些行都必须是可读的,所以这不是简单检查JTextArea中的行数。我需要删除旧行才能查看新行。

4

4 回答 4

7

使用来获取行和列

添加一个 DocumentFilter 来检查行数(传递 doc.getLength() 偏移量)并防止添加更多文本。

或者您可以创建一个虚拟的不可见 JTextArea 并在那里添加所有文本。然后测量最后允许的行并剪切文本。

于 2012-08-28T13:54:13.120 回答
7

下面是一个粗略的 DocumentFilter,它似乎可以工作。它的基本方法是让插入/追加发生,事后查询行数,如果超过最大值,则酌情从开头删除行。

当心:使用 textArea 方法计算的行数是(很可能是等待@Stani 确认)lines-between-cr,而不是布局的实际行。根据您的确切要求,它们可能适合您,也可能不适合您(如果不适合,请使用 Stan 的实用方法)

我很惊讶,不完全确定它是否安全

  • 惊讶:没有调用 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));
于 2012-08-28T14:45:30.810 回答
6

这会更有效率吗?

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();
        }
    }
}
于 2015-05-08T22:24:58.203 回答
1

我的方法将 JTextPane 的内容作为文档处理。它假定您的程序一直在一遍又一遍地将文本附加到文档的末尾,因此当您调用 doc.getCharacterElement(1) 时,您将基本上得到一个代表最早代码行的叶元素。这就是我们要删除的内容,因此我们获取该元素的开始和结束偏移量,并调用 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();
            }
        }

干杯!

于 2015-06-01T23:10:50.787 回答