2017-04-14 3 views
4

Ich versuche eine JTextPane zu verwenden, um etwas HTML zu rendern und ein CSS Stylesheet darauf anzuwenden. Das heißt, ich verwende HTMLEditorKit und StyleSheet Klassen. Ich weiß, dass alle HTMLEditorKits teilen die gleiche Standard StyleSheet Instanz, wenn Sie also dieses Standard-Stylesheet-Objekt ändern, Sie Änderungen auf Anwendungsebene anwenden (alle Komponenten, die HTML rendern).Wie initialisiert man ein JTextPane StyleSheet richtig, so dass keine andere HTML-fähige Komponente vom Stil betroffen ist?

Aber in meinem Beispiel dachte ich, dass ich dies vermieden hatte, indem ich meine eigene StyleSheet Instanz basierend auf dem Standard erstellt. Dies funktioniert jedoch nicht, wie auf dem angezeigten JTree ersichtlich ist, der nach dem Stylesheet rendert, das nur auf die JTextPane angewendet werden sollte.

import java.awt.*; 
import javax.swing.*; 
import javax.swing.text.html.*; 
import javax.swing.tree.*; 

public class TextPaneCssSpill extends JFrame { 

    private JTextPane textPane; 
    private JTree tree; 
    private JSplitPane splitPane; 

    public TextPaneCssSpill() { 
     HTMLEditorKit hed = new HTMLEditorKit(); 
     StyleSheet defaultStyle = hed.getStyleSheet(); 
     StyleSheet style = new StyleSheet(); 
     style.addStyleSheet(defaultStyle); 
     style.addRule("body {font-family:\"Monospaced\"; font-size:9px;}"); 
     style.addRule("i {color:#bababa; font-size:9px;}"); // gray italic 
     hed.setStyleSheet(style); 

     textPane = new JTextPane();   
     textPane.setEditorKit(hed); 
     textPane.setDocument(hed.createDefaultDocument()); 

     DefaultMutableTreeNode root = new DefaultMutableTreeNode(new MyNode("name", "argument"), true); 
     root.add(new DefaultMutableTreeNode(new MyNode("name", "argument"), false)); 
     root.add(new DefaultMutableTreeNode(new MyNode("name", "argument"), false)); 
     root.add(new DefaultMutableTreeNode(new MyNode("name", "argument"), false)); 
     root.add(new DefaultMutableTreeNode(new MyNode("name", "argument"), false)); 

     tree = new JTree(root); 
     tree.setCellRenderer(new MyNodeTreeRenderer()); 

     setLayout(new BorderLayout()); 
     splitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT, textPane, tree); 
     add(splitPane); 

     pack(); 
     setLocationRelativeTo(null); 
    } 

    public static void main(String[] args) { 
     SwingUtilities.invokeLater(new Runnable() { 
      @Override 
      public void run() { 
       new TextPaneCssSpill().setVisible(true); 
      } 
     }); 
    } 

    private static class MyNode { 
     private final String name; 
     private final String argument; 

     public MyNode(String name, String argument) { 
      this.name = name; 
      this.argument = argument; 
     } 

     @Override 
     public String toString() { 
      return name + " " + argument; 
     }   
    } 

    private static class MyNodeTreeRenderer extends DefaultTreeCellRenderer { 

     @Override 
     public Component getTreeCellRendererComponent(JTree tree, Object value, boolean sel, boolean expanded, boolean leaf, int row, boolean hasFocus) { 
      super.getTreeCellRendererComponent(tree, value, sel, expanded, leaf, row, hasFocus); 
      if (value instanceof DefaultMutableTreeNode) { 
       DefaultMutableTreeNode node = (DefaultMutableTreeNode) value; 
       if (node.getUserObject() instanceof MyNode) { 
        MyNode mynode = (MyNode) node.getUserObject(); 
        setText("<html>" + mynode.name + "&nbsp;<i>" + mynode.argument); 
       } 
      } 
      return this; 
     } 

    } 
} 

rendered example

Also wie kann man richtig diese Objekte initialisieren, so dass es kein CSS Verschütten über die Anwendung ist (so dass Textbereich macht CSS nach, doch der Baum nicht)?

Hinweis: Die rote Unterstreichung im obigen Bild zeigt das Problem mit dem Überlaufen an und wurde später von mir hinzugefügt (nein, es ist nicht der Renderer).

Antwort

4

Der problematische Teil meines Codes ruft HTMLEditorKit.setStyleSheet(style);. Dies ersetzt die Standard-Stylesheet-Instanz für alleHTMLEditorKits, die mir nicht bekannt war.

/** 
    * Set the set of styles to be used to render the various 
    * HTML elements. These styles are specified in terms of 
    * CSS specifications. Each document produced by the kit 
    * will have a copy of the sheet which it can add the 
    * document specific styles to. By default, the StyleSheet 
    * specified is shared by all HTMLEditorKit instances. 
    * This should be reimplemented to provide a finer granularity 
    * if desired. 
    */ 
    public void setStyleSheet(StyleSheet s) { 
     if (s == null) { 
      AppContext.getAppContext().remove(DEFAULT_STYLES_KEY); 
     } else { 
      AppContext.getAppContext().put(DEFAULT_STYLES_KEY, s); 
     } 
    } 

    /** 
    * Get the set of styles currently being used to render the 
    * HTML elements. By default the resource specified by 
    * DEFAULT_CSS gets loaded, and is shared by all HTMLEditorKit 
    * instances. 
    */ 
    public StyleSheet getStyleSheet() { 
     AppContext appContext = AppContext.getAppContext(); 
     StyleSheet defaultStyles = (StyleSheet) appContext.get(DEFAULT_STYLES_KEY); 

     if (defaultStyles == null) { 
      defaultStyles = new StyleSheet(); 
      appContext.put(DEFAULT_STYLES_KEY, defaultStyles); 
      try { 
       InputStream is = HTMLEditorKit.getResourceAsStream(DEFAULT_CSS); 
       Reader r = new BufferedReader(
         new InputStreamReader(is, "ISO-8859-1")); 
       defaultStyles.loadRules(r, null); 
       r.close(); 
      } catch (Throwable e) { 
       // on error we simply have no styles... the html 
       // will look mighty wrong but still function. 
      } 
     } 
     return defaultStyles; 
    } 

Also, was getan werden muss, ist HTMLEditorKit zu verlängern, um es Ihre Sheet zu machen zurückzukehren, ohne Vorgaben zu ändern.

import java.awt.*; 
import java.io.IOException; 
import javax.swing.*; 
import javax.swing.text.*; 
import javax.swing.text.html.*; 
import javax.swing.tree.*; 

public class TextPaneCssSpill extends JFrame { 

    private JTextPane textPane; 
    private JTree tree; 
    private JSplitPane splitPane; 
    private StyleSheet style; 

    public TextPaneCssSpill() { 
     MyHTMLEditorKit hed = new MyHTMLEditorKit(); 
     StyleSheet defaultStyle = hed.getDefaultStyleSheet(); 
     style = new StyleSheet(); 
     style.addStyleSheet(defaultStyle); 
     style.addRule("body {font-family:\"Monospaced\"; font-size:9px;}"); 
     style.addRule("i {color:#bababa; font-size:9px;}"); // gray italic 
     hed.setStyleSheet(style); 

     textPane = new JTextPane();   
     textPane.setEditorKit(hed); 
     textPane.setDocument(hed.createDefaultDocument()); 
     appendHtmlToTextPane("<i>our gray italic text</i>", textPane); 

     DefaultMutableTreeNode root = new DefaultMutableTreeNode(new MyNode("name", "argument"), true); 
     root.add(new DefaultMutableTreeNode(new MyNode("name", "argument"), false)); 
     root.add(new DefaultMutableTreeNode(new MyNode("name", "argument"), false)); 
     root.add(new DefaultMutableTreeNode(new MyNode("name", "argument"), false)); 
     root.add(new DefaultMutableTreeNode(new MyNode("name", "argument"), false)); 

     tree = new JTree(root); 
     tree.setCellRenderer(new MyNodeTreeRenderer()); 

     setDefaultCloseOperation(EXIT_ON_CLOSE); 
     setLayout(new BorderLayout()); 
     splitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT, textPane, tree); 
     add(splitPane); 

     pack(); 
     setLocationRelativeTo(null); 
    } 

    private void appendHtmlToTextPane(String str, JTextPane pane) { 
     Document doc = pane.getDocument(); 
     if (doc != null) { 
      if (doc instanceof HTMLDocument) { 
       HTMLDocument htmlDoc = (HTMLDocument) doc; 
       Element html = htmlDoc.getDefaultRootElement(); 
       if (HTML.Tag.HTML.toString().equalsIgnoreCase(html.getName())) { 
        Element body = null; 
        for (int i = 0; i < html.getElementCount(); i++) { 
         Element element = html.getElement(i); 
         if (element.getAttributes().getAttribute(StyleConstants.NameAttribute) == HTML.Tag.BODY) { 
          body = element; 
          break; 
         } 
        } 
        if (HTML.Tag.BODY.toString().equalsIgnoreCase(body.getName())) { 
         try {        
          htmlDoc.insertBeforeEnd(body, str); 
          Element lastLine = body.getElement(body.getElementCount() - 1); 
          int end = lastLine.getStartOffset(); 
          textPane.setCaretPosition(end); 

         } catch (BadLocationException e) { 
         } catch (IOException ex) { 
         } 
        } 
       } 
      } 
     } 
    } 

    public static void main(String[] args) { 
     SwingUtilities.invokeLater(new Runnable() { 
      @Override 
      public void run() { 
       new TextPaneCssSpill().setVisible(true); 
      } 
     }); 
    } 

    private static class MyNode { 
     private final String name; 
     private final String argument; 

     public MyNode(String name, String argument) { 
      this.name = name; 
      this.argument = argument; 
     } 

     @Override 
     public String toString() { 
      return name + " " + argument; 
     }   
    } 

    private static class MyNodeTreeRenderer extends DefaultTreeCellRenderer { 

     @Override 
     public Component getTreeCellRendererComponent(JTree tree, Object value, boolean sel, boolean expanded, boolean leaf, int row, boolean hasFocus) { 
      super.getTreeCellRendererComponent(tree, value, sel, expanded, leaf, row, hasFocus); 
      if (value instanceof DefaultMutableTreeNode) { 
       DefaultMutableTreeNode node = (DefaultMutableTreeNode) value; 
       if (node.getUserObject() instanceof MyNode) { 
        MyNode mynode = (MyNode) node.getUserObject(); 
        setText("<html>" + mynode.name + "&nbsp;<i>" + mynode.argument); 
       } 
      } 
      return this; 
     } 

    } 

    /** 
    * Avoid setting the stylesheet for all HTMLEditorKit instances. 
    */ 
    private static class MyHTMLEditorKit extends HTMLEditorKit { 

     private StyleSheet myStyle; 

     @Override 
     public StyleSheet getStyleSheet() { 
      return myStyle == null ? super.getStyleSheet() : myStyle; 
     } 

     @Override 
     public void setStyleSheet(StyleSheet s) { 
      this.myStyle = s; 
     } 

     public StyleSheet getDefaultStyleSheet() { 
      return super.getStyleSheet(); 
     } 

     public void setDefaultStyleSheet(StyleSheet s) { 
      super.setStyleSheet(s); 
     } 

    } 
} 

fixed version

Verwandte Themen