更改 JTextPane 中现有 HTMLDocument 内容的样式

发布于 2024-11-06 04:51:21 字数 1706 浏览 0 评论 0原文

我正在尝试构建一个使用 JTextPane 来显示对话的聊天客户端。我在突出显示用户选择的聊天参与者过去的句子时遇到问题。实现此功能时,我需要坚持使用 HTMLDocument,因为某些内容必须是 HTML。

最好的想法似乎是为参与对话的每个用户使用不同的命名样式。这个想法是,当需要突出显示特定人的文本时,我只需更新他的个人风格,他所说的所有内容都应该像魔术一样突出显示。不幸的是这不起作用。

因此,要添加文本,我使用:

public void addMessage(String from, String message){
    HTMLDocument doc = (HTMLDocument) textPane.getStyledDocument();
    if(doc != null){
        try {
            String stylename = "from_" + from;
            if(textPane.getStyle(stylename) == null){
                LOG.debug("Did not find style. Adding new: " + stylename);
                Style nameStyle = textPane.addStyle(stylename, null);
                StyleConstants.setForeground(nameStyle, Color.black);
                StyleConstants.setBold(nameStyle, true);
            }else{
                LOG.debug("Found existing style: " + textPane.getStyle(stylename));
            }
            doc.insertString(doc.getLength(), from + ": ", textPane.getStyle(stylename));
            doc.insertString(doc.getLength(), message + "\n", null);
        } catch (BadLocationException ble) {
            LOG.error("Could not insert text to tab");
        }
    }
}

到目前为止一切顺利...文本按照我的意愿显示在文本窗格中。但是,当我尝试在将来的某个时刻更新样式表并调用:

public void highlight(String name, boolean highlight){
    Style fromStyle = textPane.getStyle("from_" + name);
    if(fromStyle != null){
        LOG.debug("found style, changing color");
        StyleConstants.setForeground(fromStyle, Color.red);
    }else{
        LOG.debug("fromStyle was NULL");
    }
}

..我可以看到样式已找到并且我的代码已执行 - 但屏幕上没有任何变化。

我想询问您是否对我如何尝试解决此问题有任何建议。有没有办法让这个工作与命名样式一起工作,或者我应该采取一些完全不同的方法?

谢谢

I am trying to build a chat client that uses JTextPane to display the conversations. I am having problems with highlighting the past sentences of a chat-participant chosen by the user. When implementing this I need to stick to using HTMLDocument as some of the content has to be HTML.

The best idea seemed to be using a different named styles for each user participating in the conversation. The idea is that when the text of a particular person needs to be highlighted, I just update his personal style and everything he has said should get highlighted as by magic. Unfortunately this does not work.

So to add text I use:

public void addMessage(String from, String message){
    HTMLDocument doc = (HTMLDocument) textPane.getStyledDocument();
    if(doc != null){
        try {
            String stylename = "from_" + from;
            if(textPane.getStyle(stylename) == null){
                LOG.debug("Did not find style. Adding new: " + stylename);
                Style nameStyle = textPane.addStyle(stylename, null);
                StyleConstants.setForeground(nameStyle, Color.black);
                StyleConstants.setBold(nameStyle, true);
            }else{
                LOG.debug("Found existing style: " + textPane.getStyle(stylename));
            }
            doc.insertString(doc.getLength(), from + ": ", textPane.getStyle(stylename));
            doc.insertString(doc.getLength(), message + "\n", null);
        } catch (BadLocationException ble) {
            LOG.error("Could not insert text to tab");
        }
    }
}

So far so good... The text gets displayed in the textPane as I wished. However when I try to update the stylesheet at some future point and call:

public void highlight(String name, boolean highlight){
    Style fromStyle = textPane.getStyle("from_" + name);
    if(fromStyle != null){
        LOG.debug("found style, changing color");
        StyleConstants.setForeground(fromStyle, Color.red);
    }else{
        LOG.debug("fromStyle was NULL");
    }
}

..I can see that the style is found and my code gets executed - yet nothing changes on the screen.

I would like to ask if you have any suggestions on how I might try to resolve this issue. Is there a way to make this work with named styles or should I take some completely different approach?

Thank you

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

等风来 2024-11-13 04:51:21

您刚刚修改了 Style 对象,仍然需要使用 setCharacterAttributes

You just modified the Style object, you still have to apply the modified Style using setCharacterAttributes.

夜未央樱花落 2024-11-13 04:51:21

从那时起,我创建了一个适合我的解决方案。我将在这里为感兴趣的人发布一个功能测试用例。我最终得到了一个解决方案,我更新了 StyleSheet 中的样式类,然后为每个段落元素调用 htmlDocument.setParagraphAttributes 。

import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.EventQueue;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;

import javax.swing.JFrame;
import javax.swing.JTextPane;
import javax.swing.SwingUtilities;
import javax.swing.text.BadLocationException;
import javax.swing.text.Element;
import javax.swing.text.html.HTMLDocument;
import javax.swing.text.html.HTMLEditorKit;
import javax.swing.text.html.StyleSheet;

public class StyleChangeTest extends JFrame {

    public final static int APP_WIDTH = 640;
    public final static int APP_HEIGHT = 400;
    public JTextPane jTextPane;
    public StyleSheet styleSheet;
    public HTMLDocument htmlDocument;
    public HTMLEditorKit htmlEditorKit;
    public Element bodyElement;

    public static StyleChangeTest jTextPaneApp;

    public static void main(String[] args) throws InterruptedException, InvocationTargetException{
        EventQueue.invokeAndWait(new Runnable() {
            public void run() {
                try {
                    jTextPaneApp = new StyleChangeTest();
                    jTextPaneApp.setVisible(true);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
        System.out.println("Started");
        Thread.currentThread().sleep(1000);
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                try {
                    jTextPaneApp.change();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
        System.out.println("Finished");
    }

    public StyleChangeTest(){
        setSize(APP_WIDTH, APP_HEIGHT);
        setResizable(false);
        setTitle("JTextPane App");

        styleSheet = new StyleSheet();
        styleSheet.addRule(".someclass1 {color: blue;}");
        styleSheet.addRule(".someclass2 {color: green;}");

        htmlEditorKit = new HTMLEditorKit();
        htmlEditorKit.setStyleSheet(styleSheet);
        htmlDocument = (HTMLDocument) htmlEditorKit.createDefaultDocument();
        jTextPane = new JTextPane();
        jTextPane.setEditorKit(htmlEditorKit);
        jTextPane.setDocument(htmlDocument);

        try {
            Element htmlElement = htmlDocument.getRootElements()[0];
            bodyElement = htmlElement.getElement(0);

            Container contentPane = getContentPane();
            contentPane.setLayout(new BorderLayout());
            contentPane.add(jTextPane, BorderLayout.CENTER);
            addWindowListener(new WindowAdapter(){
                public void windowClosing(WindowEvent e){
                    System.exit(0);
                }
            });

            addContent("<font class=someclass1>test 1</font><br>");
            addContent("<font class=someclass2>test 2</font><br>");

        } catch (Exception e) {
            e.printStackTrace();
        }
    }


    public void reapplyStyles() {
        System.out.println("Reformating...");
        Element sectionElem = bodyElement.getElement(bodyElement.getElementCount() - 1);
        int paraCount = sectionElem.getElementCount();
        for (int i=0; i<paraCount; i++) {
            Element paraElem = sectionElem.getElement(i);
            //System.out.println("\tParagraph: " + (i+1) + " - " + paraElem);
            int rangeStart = paraElem.getStartOffset();
            int rangeEnd = paraElem.getEndOffset();
            htmlDocument.setParagraphAttributes(rangeStart, rangeEnd-rangeStart, paraElem.getAttributes(), true);
        }
    }


    public void change() throws BadLocationException, IOException{
        styleSheet = htmlEditorKit.getStyleSheet();
        styleSheet.addRule(".someclass1 {color: red;}");
        reapplyStyles();
        addContent("<font class=someclass1>test 3</font><br>");
    }


    private void addContent(String content) throws BadLocationException, IOException{
        Element contentElement = bodyElement.getElement(bodyElement.getElementCount() - 1);

        StringBuffer sbHtml = new StringBuffer();
        sbHtml.append("<font class=someclass>" + content + "</font><br>");

        htmlDocument.insertBeforeEnd(contentElement, sbHtml.toString());
    }

}

I have since created a solution which works for me. I will post here a functioning testcase for anyone interested. I ended up with a solution where I updated the style class in the StyleSheet and then called htmlDocument.setParagraphAttributes for every paragraph element.

import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.EventQueue;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;

import javax.swing.JFrame;
import javax.swing.JTextPane;
import javax.swing.SwingUtilities;
import javax.swing.text.BadLocationException;
import javax.swing.text.Element;
import javax.swing.text.html.HTMLDocument;
import javax.swing.text.html.HTMLEditorKit;
import javax.swing.text.html.StyleSheet;

public class StyleChangeTest extends JFrame {

    public final static int APP_WIDTH = 640;
    public final static int APP_HEIGHT = 400;
    public JTextPane jTextPane;
    public StyleSheet styleSheet;
    public HTMLDocument htmlDocument;
    public HTMLEditorKit htmlEditorKit;
    public Element bodyElement;

    public static StyleChangeTest jTextPaneApp;

    public static void main(String[] args) throws InterruptedException, InvocationTargetException{
        EventQueue.invokeAndWait(new Runnable() {
            public void run() {
                try {
                    jTextPaneApp = new StyleChangeTest();
                    jTextPaneApp.setVisible(true);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
        System.out.println("Started");
        Thread.currentThread().sleep(1000);
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                try {
                    jTextPaneApp.change();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
        System.out.println("Finished");
    }

    public StyleChangeTest(){
        setSize(APP_WIDTH, APP_HEIGHT);
        setResizable(false);
        setTitle("JTextPane App");

        styleSheet = new StyleSheet();
        styleSheet.addRule(".someclass1 {color: blue;}");
        styleSheet.addRule(".someclass2 {color: green;}");

        htmlEditorKit = new HTMLEditorKit();
        htmlEditorKit.setStyleSheet(styleSheet);
        htmlDocument = (HTMLDocument) htmlEditorKit.createDefaultDocument();
        jTextPane = new JTextPane();
        jTextPane.setEditorKit(htmlEditorKit);
        jTextPane.setDocument(htmlDocument);

        try {
            Element htmlElement = htmlDocument.getRootElements()[0];
            bodyElement = htmlElement.getElement(0);

            Container contentPane = getContentPane();
            contentPane.setLayout(new BorderLayout());
            contentPane.add(jTextPane, BorderLayout.CENTER);
            addWindowListener(new WindowAdapter(){
                public void windowClosing(WindowEvent e){
                    System.exit(0);
                }
            });

            addContent("<font class=someclass1>test 1</font><br>");
            addContent("<font class=someclass2>test 2</font><br>");

        } catch (Exception e) {
            e.printStackTrace();
        }
    }


    public void reapplyStyles() {
        System.out.println("Reformating...");
        Element sectionElem = bodyElement.getElement(bodyElement.getElementCount() - 1);
        int paraCount = sectionElem.getElementCount();
        for (int i=0; i<paraCount; i++) {
            Element paraElem = sectionElem.getElement(i);
            //System.out.println("\tParagraph: " + (i+1) + " - " + paraElem);
            int rangeStart = paraElem.getStartOffset();
            int rangeEnd = paraElem.getEndOffset();
            htmlDocument.setParagraphAttributes(rangeStart, rangeEnd-rangeStart, paraElem.getAttributes(), true);
        }
    }


    public void change() throws BadLocationException, IOException{
        styleSheet = htmlEditorKit.getStyleSheet();
        styleSheet.addRule(".someclass1 {color: red;}");
        reapplyStyles();
        addContent("<font class=someclass1>test 3</font><br>");
    }


    private void addContent(String content) throws BadLocationException, IOException{
        Element contentElement = bodyElement.getElement(bodyElement.getElementCount() - 1);

        StringBuffer sbHtml = new StringBuffer();
        sbHtml.append("<font class=someclass>" + content + "</font><br>");

        htmlDocument.insertBeforeEnd(contentElement, sbHtml.toString());
    }

}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文