2011-05-09 54 views
1

我正嘗試構建使用JTextPane顯示對話的聊天客戶端。我在突出顯示用戶選擇的聊天參與者的過去句子時遇到問題。在實現這個時,我需要堅持使用HTMLDocument,因爲一些內容必須是HTML。在JTextPane中更改現有HTMLDocument內容的樣式

對於參與對話的每個用戶來說,最好的想法似乎是使用不同的命名樣式。這個想法是,當一個特定的人的文本需要突出顯示時,我只是更新他的個人風格,他所說的一切都應該通過魔法突出顯示。不幸的是,這是行不通的。

所以添加文字使用:

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"); 
     } 
    } 
} 

到目前爲止好......我希望該文本被顯示在textPane。然而,當我試圖在未來的某個時刻更新的樣式表,並呼籲:

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"); 
    } 
} 

..我可以看到風格被發現,我的代碼得到執行 - 但在屏幕上沒有什麼變化。

我想問你是否有任何建議可以嘗試解決這個問題。有沒有辦法使用命名樣式進行這項工作,還是應該採取一些完全不同的方法?

謝謝

回答

1

你剛修改過的Style對象,你還是要申請使用setCharacterAttributes修改Style

+0

但爲此,我將不得不自己找到所有文本範圍來應用樣式。我期待着一個行爲,即修改一個styleclass,將這些修改應用到使用該特定styleclass的所有範圍。 – Mindgamer 2011-05-09 21:00:51

+0

@Mindgamer:據我所知java不提供你想要的行爲。你將不得不跟蹤自己的線路和偏移量。 – lesmana 2011-05-10 08:31:46

+0

謝謝你的建議 – Mindgamer 2011-05-10 16:14:35

1

我已經創建了一個適合我的解決方案。我會在這裏發佈一個有效的測試用例。我結束了一個解決方案,我更新了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()); 
    } 

}