Swing只读取我的AbstractDocument.Content的第一个字符。我究竟做错了什么?

时间:2013-11-24 13:09:35

标签: java swing document large-files

我有一个功能,我应该显示一个巨大的文本文件。所以我想我会尝试在磁盘超过一定大小时将内存映射到磁盘上。

文本至少是不可变的,这比编写支持相同大小的完整编辑器要容易。

这是我到目前为止所拥有的:

public class CharBufferContent implements AbstractDocument.Content {
    private final CharBuffer charBuffer;
    private final int length;

    public CharBufferContent(CharBuffer charBuffer) {
        this.charBuffer = charBuffer;
        length = charBuffer.length();
    }

    public Position createPosition(int offset) throws BadLocationException {
        return new ImmutablePosition(offset);
    }

    public int length() {
        return length;
    }

    public UndoableEdit insertString(int where, String string)
            throws BadLocationException {
        throw new UnsupportedOperationException("Document is immutable");
    }

    public UndoableEdit remove(int where, int nItems) throws BadLocationException {
        throw new UnsupportedOperationException("Document is immutable");
    }

    public String getString(int where, int length) throws BadLocationException {
        if (where < 0 || where + length > this.length) {
            throw new BadLocationException("Invalid range", this.length);
        }

        char[] out = new char[length];
        charBuffer.position(where);
        charBuffer.get(out);
        return new String(out);
    }

    public void getChars(int where, int length, Segment segment)
            throws BadLocationException {
        if (where < 0 || where + length > this.length) {
            throw new BadLocationException("Invalid range", this.length);
        }

        // This will be inefficient, but I'm just trying to get it working first.
        segment.array = new char[length];
        charBuffer.position(where);
        charBuffer.get(segment.array, 0, length);
        segment.offset = 0;
        segment.count = length;
    }

    private static class ImmutablePosition implements Position {
        private final int offset;

        private ImmutablePosition(int offset) {
            this.offset = offset;
        }

        @Override
        public int getOffset() {
            return offset;
        }
    }
}

我写了一个小测试程序,它只使用内存缓冲区来测试它:

public class Test implements Runnable {
    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Test());
    }

    public void run() {
        CharBuffer charBuffer = CharBuffer.wrap("This is a fairly simple test, " +
            "so nothing should go wrong, right?\n");
        AbstractDocument.Content content = new CharBufferContent(charBuffer);
        final Document document = new PlainDocument(content);

        JTextArea text = new JTextArea(document);
        text.setEditable(false);

        JScrollPane textScroll = new JScrollPane(text);
        textScroll.setPreferredSize(new Dimension(600, 500));

        JFrame frame = new JFrame("Test");
        frame.setLayout(new BorderLayout());
        frame.add(textScroll, BorderLayout.CENTER);
        frame.pack();
        frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        frame.setVisible(true);
    }
}

当我运行它时,窗口显示“T”。在调试器中,我可以看到Swing只调用length()getChars()。每次拨打getChars()的电话都有where == 0length == 1。所以它只有一个字符可以显示是有意义的,但是Swing调用我的代码并且只询问第一个字符似乎很奇怪,即使我可以看到length()返回完整长度文本。

当我使用StringContent作为实现运行相同的测试时,使用文档的全长调用getChars()

这个API中没有太多看起来可能会出错,所以我很困惑。

这里发生了什么?

1 个答案:

答案 0 :(得分:1)

我并不精通文档API,但我的理解是AbstractDocument.Content预计不会预先配备自己的文本。在这种情况下,AbstractDocument不知道该怎么做。如果您使用StringContent尝试此操作,您将看到同样的问题:

content = new StringContent();
content.insertString(0, "some text");
final AbstractDocument document = new PlainDocument(content);

这只显示领先的's'。显然,AbstractDocument在插入文档的末尾为插入符号建模一个额外的有效位置,并且它希望其内容的长度为其实际长度的+1以支持它,我认为这是第一个字符的事实的起源。出现。

如果您在创建文档之后只调用,那么它似乎可以显示所有文本,但我认为这可能只是运气。如果以这种方式插入的字符串包含换行符,它将始终忽略它们,因为它们未被建模为单独的文档元素,因为它们是必需的。

我认为实现这项工作的唯一方法是直接实现Document,而不是AbstractDocument.Content。这是一个更复杂的界面,但这确实有效:

StringContent.insertString