Нарисуйте строки RTF/HTML в настраиваемый компонент Swing

В моем приложении Swing пользователи вводят стилизованный текст в JTextPane., который использует RTFEditorKit (также возможен HTML).

Затем мне нужно отобразить многие из этих стилизованных заметок в определенных координатах в пользовательском компоненте.

Я бы подумал, что View.paint здесь был бы полезен, но я не могу создать пригодный для использования объект View.

У меня есть следующий метод:

public View createView() throws IOException, BadLocationException {
 RTFEditorKit kit = new RTFEditorKit();
 final Document document = kit.createDefaultDocument();
 kit.read(new ByteArrayInputStream(text.getBytes("UTF-8")), document, 0);
 return kit.getViewFactory().create(document.getDefaultRootElement());
}

Это возвращает javax.swing.text.BoxView со следующими атрибутами:

majorAxis = 1
majorSpan = 0
minorSpan = 0
majorReqValid = false
minorReqValid = false
majorRequest = null
minorRequest = null
majorAllocValid = false
majorOffsets = {int[0]@2321}
majorSpans = {int[0]@2322}
minorAllocValid = false
minorOffsets = {int[0]@2323}
minorSpans = {int[0]@2324}
tempRect = {java.awt.Rectangle@2325}"java.awt.Rectangle[x=0,y=0,width=0,height=0]"
children = {javax.swing.text.View[1]@2326}
nchildren = 0
left = 0
right = 0
top = 0
bottom = 0
childAlloc = {java.awt.Rectangle@2327}"java.awt.Rectangle[x=0,y=0,width=0,height=0]"
parent = null
elem = {javax.swing.text.DefaultStyledDocument$SectionElement@2328}"BranchElement(section) 0,35\n"

Обратите внимание, что parent = null и nchildren = 0. Это означает, что здесь нет ничего действительно полезного. Я могу собрать что-нибудь, вызвав JTextPane.getUI().paint, но текстовая панель должна быть видна, и мне кажется, что это неправильный способ сделать это.

Есть ли способ получить визуальное представление содержимого RTF без рендеринга фактического JTextPane?


person Sam Barnum    schedule 04.10.2009    source источник


Ответы (2)


Ознакомьтесь с классом ScreenImage, который позволяет создавать BufferedImage. любого компонента Swing. Это также должно работать для компонентов Swing, которые не видны, но да, вам сначала нужно выполнить рендеринг.

person camickr    schedule 04.10.2009
comment
Спасибо за ссылку, это больше похоже на снимок компонента, который уже виден на экране. Я хотел бы использовать метод штамповки для рендеринга блоков стилизованного текста в разных местах моего пользовательского компонента. - person Sam Barnum; 05.10.2009
comment
Я не знаю, что такое штамповка. Возможно, я не понимаю вопроса, но идея в том, что вы можете создать изображение из невидимого компонента. Затем вы можете создавать дополнительные изображения для рендеринга на вашем пользовательском компоненте. Суть в том, что вам не нужен видимый компонент для создания образа. - person camickr; 05.10.2009

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

private static void testRtfRender() {
    String s = "{\\rtf1\\ansi\n" +
            "{\\fonttbl\\f0\\fnil Monospaced;\\f1\\fnil Lucida Grande;}\n" +
            "\n" +
            "\\f1\\fs26\\i0\\b0\\cf0 this is a \\b test\\b0\\par\n" +
            "}";

    JTextPane pane = new JTextPane();
    pane.setContentType("text/rtf");
    pane.setText(s);

    final Dimension preferredSize = pane.getUI().getPreferredSize(pane);
    int w = preferredSize.width;
    int h = preferredSize.height;

    pane.setSize(w, h);
    pane.addNotify();
    pane.validate();

    // would be nice to use this box view instead of instantiating a UI
    // however, unless you call setParent() on the view it's useless
    // What should the parent of a root element be?
    //BoxView view = (BoxView) pane.getEditorKit().getViewFactory().create(pane.getStyledDocument().getDefaultRootElement());
    //view.paint(d, new Rectangle(w, h));

    BufferedImage img = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
    final Graphics2D d = img.createGraphics();
    d.setClip(0, 0, w, h); // throws a NullPointerException if I leave this out
    pane.getUI().paint(d, pane);
    d.dispose();
    JOptionPane.showMessageDialog(null, new JLabel(new ImageIcon(img)));
}
person Sam Barnum    schedule 04.10.2009