Proper manner create Class, JTree, DefaultTreeCellRenderer using JTextPane

青春壹個敷衍的年華 提交于 2019-12-20 07:27:07

问题


I have this class in order to show multiple colors in a leaf using JTree...

The class is TextPaneDefaultTreeCellRenderer

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

public class TextPaneDefaultTreeCellRenderer extends DefaultTreeCellRenderer {

  TextPaneTreeCellRenderer textPaneScrollPane = new TextPaneTreeCellRenderer();

  public TextPaneDefaultTreeCellRenderer() {
    initialize();
  }

  private void initialize() {
    textPaneScrollPane.setBackgroundNonSelectionColor(getBackgroundNonSelectionColor());
    textPaneScrollPane.setBackgroundSelectionColor(getBackgroundSelectionColor());
    textPaneScrollPane.setTextNonSelectionColor(getTextNonSelectionColor());
    textPaneScrollPane.setTextSelectionColor(getTextSelectionColor());
  }

  @Override
  public Component getTreeCellRendererComponent(JTree tree,
      Object value, boolean selected, boolean expanded, boolean leaf,
      int row, boolean hasFocus) {
    if (leaf) {
      DefaultMutableTreeNode node = (DefaultMutableTreeNode) value;
      Object obj = node.getUserObject();
      if (obj != null) {
        if (obj instanceof DecoratedText || obj instanceof DecoratedText[]) {
          if (textPaneScrollPane == null) {
            System.out.println("textPaneScrollPane:" + textPaneScrollPane);
          }
          return textPaneScrollPane.getTreeCellRendererComponent(tree, value,
              selected, expanded, leaf, row, hasFocus);
        }
      }
    }
    return super.getTreeCellRendererComponent(tree, value, selected,
        expanded, leaf, row, hasFocus);
  }
}

class TextPaneTreeCellRenderer extends DefaultTreeCellRenderer {

  JTextPane textPane;

  public TextPaneTreeCellRenderer() {
    textPane = new JTextPane();
    add(textPane);
  }

  @Override
  public void setBackgroundNonSelectionColor(Color color) {
    this.backgroundNonSelectionColor = color;
  }

  @Override
  public void setBackgroundSelectionColor(Color color) {
    this.backgroundSelectionColor = color;
  }

  @Override
  public void setTextNonSelectionColor(Color color) {
    this.textNonSelectionColor = color;
  }

  @Override
  public void setTextSelectionColor(Color color) {
    this.textSelectionColor = color;
  }

  @Override
  public Component getTreeCellRendererComponent(JTree tree,
      Object value, boolean selected, boolean expanded, boolean leaf,
      int row, boolean hasFocus) {

    DefaultMutableTreeNode node = (DefaultMutableTreeNode) value;
    Object object = node.getUserObject();

    if (selected) {
      setForeground(textSelectionColor);
      setBackground(backgroundSelectionColor);
      textPane.setForeground(textSelectionColor);
      textPane.setBackground(backgroundSelectionColor);
    } else {
      setForeground(textNonSelectionColor);
      setBackground(backgroundNonSelectionColor);
      textPane.setForeground(textNonSelectionColor);
      textPane.setBackground(backgroundNonSelectionColor);
    }

    textPane.setText("");
    Document doc = textPane.getStyledDocument();
    if (object != null && object instanceof DecoratedText) {
      DecoratedText decText = (DecoratedText) object;
      try {
        doc.insertString(doc.getLength(), decText.getText(), getAttributeSet(decText));
      } catch (BadLocationException ex) {
        Logger.getLogger(TextPaneTreeCellRenderer.class.getName()).log(Level.SEVERE, null, ex);
      }
    } else if (object != null && object instanceof DecoratedText[]) {
      DecoratedText[] arrayDecText = (DecoratedText[]) object;
      for (DecoratedText decText : arrayDecText) {
        try {
          //doc.insertString(doc.getLength(), decText.getText(), getAttributeSet(decText));
          doc.insertString(doc.getLength(), decText.getText(), decText.getAttributeSet(textPane));
        } catch (BadLocationException ex) {
          System.out.println("decText:" + decText);
          System.out.println("arrayDecText:" + arrayDecText);
          System.out.println("doc:" + doc.getLength());
          Logger.getLogger(TextPaneTreeCellRenderer.class.getName()).log(Level.SEVERE, null, ex);
        }
      }
    } else {
      return new DefaultTreeCellRenderer().getTreeCellRendererComponent(tree,
          value, leaf, expanded, leaf, row, hasFocus);
    }
    return textPane;
  }

  private SimpleAttributeSet getAttributeSet(DecoratedText decoratedText) {
    SimpleAttributeSet attrSet = new SimpleAttributeSet();
    if (decoratedText != null) {
      if (decoratedText.getBackground() != null) {
        StyleConstants.setBackground(attrSet, decoratedText.getBackground());
      } else {
        StyleConstants.setBackground(attrSet, textPane.getBackground());
      }
      if (decoratedText.getForeground() != null) {
        StyleConstants.setForeground(attrSet, decoratedText.getForeground());
      } else {
        StyleConstants.setForeground(attrSet, textPane.getForeground());
      }
      Font font;
      if (decoratedText.getFont() != null) {
        font = decoratedText.getFont();
      } else {
        font = textPane.getFont();
      }
      StyleConstants.setFontFamily(attrSet, font.getFamily());
      StyleConstants.setItalic(attrSet, font.isItalic());
      StyleConstants.setBold(attrSet, font.isBold());
      StyleConstants.setFontSize(attrSet, font.getSize());
    }
    return attrSet;
  }

}

Alternative class is TreeCellRendererTextPane

import java.awt.Component;
import java.util.logging.*;
import javax.swing.*;
import javax.swing.text.*;
import javax.swing.tree.*;

public class TreeCellRendererTextPane extends JTextPane implements TreeCellRenderer {

  @Override
  public Component getTreeCellRendererComponent(JTree tree,
      Object value, boolean selected, boolean expanded, boolean leaf,
      int row, boolean hasFocus) {
    if (leaf) {
      DefaultMutableTreeNode node = (DefaultMutableTreeNode) value;
      Object obj = node.getUserObject();
      if (obj != null) {
        if (obj instanceof DecoratedText || obj instanceof DecoratedText[]) {
          this.setText("");
          Document doc = this.getStyledDocument();
          if (obj instanceof DecoratedText) {
            DecoratedText decText = (DecoratedText) obj;
            try {
              doc.insertString(doc.getLength(), decText.getText(), decText.getAttributeSet(this));
            } catch (BadLocationException ex) {
              Logger.getLogger(TextPaneTreeCellRenderer.class.getName()).log(Level.SEVERE, null, ex);
            }
          }
          if (obj instanceof DecoratedText[]) {
            DecoratedText[] arrayDecText = (DecoratedText[]) obj;
            for (DecoratedText decText : arrayDecText) {
              try {
                doc.insertString(doc.getLength(), decText.getText(), decText.getAttributeSet(this));
              } catch (BadLocationException ex) {
                System.out.println("decText:" + decText);
                System.out.println("arrayDecText:" + arrayDecText);
                System.out.println("doc:" + doc.getLength());
                Logger.getLogger(TextPaneTreeCellRenderer.class.getName()).log(Level.SEVERE, null, ex);
              }
            }
          }
        } else {
          return new DefaultTreeCellRenderer().getTreeCellRendererComponent(tree,
              value, leaf, expanded, leaf, row, hasFocus);
        }
      }
    }
    return this;
  }
}

As you can see the Root (not leaf is not shown properly, the folder are omitted, the words only shown the first letter)

My other class is DecoratedText:

import java.awt.*;
import javax.swing.JTextPane;
import javax.swing.text.*;

public class DecoratedText {

  private String text;
  private Color background;// = new JLabel().getBackground();
  private Color foreground;// = new JLabel().getForeground();
  private Font font;// = new JLabel().getFont();

  public DecoratedText(String text) {
    this.text = text;
  }

  public DecoratedText(String text, Font font) {
    this.text = text;
    this.font = font;
  }

  public DecoratedText(String text, Color foreground) {
    this.text = text;
    this.foreground = foreground;
  }

  public DecoratedText(String text, Color foreground, Font font) {
    this.text = text;
    this.foreground = foreground;
    this.font = font;
  }

  public DecoratedText(Color background, String text) {
    this.background = background;
    this.text = text;
  }

  public DecoratedText(Color background, String text, Font font) {
    this.background = background;
    this.text = text;
    this.font = font;
  }

  public DecoratedText(Color background, String text, Color foreground) {
    this.background = background;
    this.text = text;
    this.foreground = foreground;
  }

  public DecoratedText(Color background, String text, Color foreground, Font font) {
    this.background = background;
    this.text = text;
    this.foreground = foreground;
    this.font = font;
  }

  public String getText() {
    return text;
  }

  public void setText(String text) {
    this.text = text;
  }

  public Color getBackground() {
    return background;
  }

  public void setBackground(Color background) {
    this.background = background;
  }

  public Color getForeground() {
    return foreground;
  }

  public void setForeground(Color foreground) {
    this.foreground = foreground;
  }

  public Font getFont() {
    return font;
  }

  public void setFont(Font font) {
    this.font = font;
  }

  @Override
  public String toString() {
    return "DecoratedText{" + "text=" + text + ", background=" + background
        + ", foreground=" + foreground + ", font=" + font + "}";
  }

  public SimpleAttributeSet getAttributeSet(JTextPane textPane) {
    SimpleAttributeSet attrSet = new SimpleAttributeSet();
    if (getBackground() != null) {
      StyleConstants.setBackground(attrSet, getBackground());
    } else {
      StyleConstants.setBackground(attrSet, textPane.getBackground());
    }
    if (getForeground() != null) {
      StyleConstants.setForeground(attrSet, getForeground());
    } else {
      StyleConstants.setForeground(attrSet, textPane.getForeground());
    }
    Font font;
    if (getFont() != null) {
      font = getFont();
    } else {
      font = textPane.getFont();
    }
    StyleConstants.setFontFamily(attrSet, font.getFamily());
    StyleConstants.setItalic(attrSet, font.isItalic());
    StyleConstants.setBold(attrSet, font.isBold());
    StyleConstants.setFontSize(attrSet, font.getSize());
    return attrSet;
  }

}

The problem with the first Class (TextPaneDefaultTreeCellRenderer) is this nullpointerexception using nimbus LAF, but with another LAF, aqua, metal, motif, gtk and windows the problem is not presented.

And Trying to do Divide and Conquer, this question is not about what fails? else is my class fine implemented?

Discover Reason of NullPointerException in Java Native Classes, SynthTreeUI using LAF Nimbus


回答1:


The problem with the first Class (TextPaneDefaultTreeCellRenderer) is this nullpointerexception using nimbus LAF, ...

Even when using NimbusLookAndFeel in my environment(1.8.0_181, Windows 10) NullPointerException does not occur for the TextPaneDefaultTreeCellRenderer...

the folder are omitted

It would be works fine to layout JTextPane and JLabel for icon in JPanel and use this as TreeCellRenderer.

import java.awt.*;
import java.awt.event.*;
import java.util.*;
import java.util.logging.*;
import javax.swing.*;
import javax.swing.text.*;
import javax.swing.tree.*;

public class TextPaneTreeCellRendererTest {
  public Component makeUI() {
    JTree tree0 = new JTree(makeModel());

    // JTree tree1 = new JTree(makeModel());
    // tree1.setCellRenderer(new TextPaneDefaultTreeCellRenderer());

    // JTree tree2 = new JTree(makeModel());
    // tree2.setCellRenderer(new TextPaneTreeCellRenderer());

    // JTree tree3 = new JTree(makeModel());
    // tree3.setCellRenderer(new TreeCellRendererTextPane());

    JTree tree = new JTree(makeModel());
    tree.setRowHeight(24);
    tree.setCellRenderer(new CustomTreeCellRenderer());

    JTabbedPane tabs = new JTabbedPane();
    tabs.add("DefaultTreeCellRenderer", new JScrollPane(tree0));
    // tabs.add("TextPaneDefaultTreeCellRenderer", new JScrollPane(tree1));
    // tabs.add("TextPaneTreeCellRenderer", new JScrollPane(tree2));
    // tabs.add("TreeCellRendererTextPane", new JScrollPane(tree3));
    tabs.add("CustomTreeCellRenderer", new JScrollPane(tree));
    return tabs;
  }
  private static TreeModel makeModel() {
    DefaultMutableTreeNode root = new DefaultMutableTreeNode("/Users/");
    DefaultMutableTreeNode parent;

    parent = new DefaultMutableTreeNode("<html>/Users/...<span style='color:red'>colors: <span style='color:blue'>blue");
    root.add(parent);
    String txt = "<html><span style='color:red'>Line 6</span> : <span style='color:blue'>!!!!!!!! on <span style='Color:green'>CentOS</span> 7</span>";
    parent.add(new DefaultMutableTreeNode(txt));
    parent.add(new DefaultMutableTreeNode(new DecoratedText("blue", Color.BLUE)));
    parent.add(new DefaultMutableTreeNode(new DecoratedText("pink", Color.PINK)));
    parent.add(new DefaultMutableTreeNode(new DecoratedText("red", Color.RED)));
    return new DefaultTreeModel(root);
  }
  public static void main(String[] args) {
    EventQueue.invokeLater(() -> {
      try {
        UIManager.setLookAndFeel("javax.swing.plaf.nimbus.NimbusLookAndFeel");
      } catch (Exception e) {
        e.printStackTrace();
      }
      JFrame f = new JFrame();
      f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
      f.getContentPane().add(new TextPaneTreeCellRendererTest().makeUI());
      f.setSize(640, 480);
      f.setLocationRelativeTo(null);
      f.setVisible(true);
    });
  }
}

class DecoratedText {
  private String text;
  private Color background; // = new JLabel().getBackground();
  private Color foreground; // = new JLabel().getForeground();
  private Font font; // = new JLabel().getFont();

  public DecoratedText(String text) {
    this.text = text;
  }

  public DecoratedText(String text, Font font) {
    this.text = text;
    this.font = font;
  }

  public DecoratedText(String text, Color foreground) {
    this.text = text;
    this.foreground = foreground;
  }

  public DecoratedText(String text, Color foreground, Font font) {
    this.text = text;
    this.foreground = foreground;
    this.font = font;
  }

  public DecoratedText(Color background, String text) {
    this.background = background;
    this.text = text;
  }

  public DecoratedText(Color background, String text, Font font) {
    this.background = background;
    this.text = text;
    this.font = font;
  }

  public DecoratedText(Color background, String text, Color foreground) {
    this.background = background;
    this.text = text;
    this.foreground = foreground;
  }

  public DecoratedText(Color background, String text, Color foreground, Font font) {
    this.background = background;
    this.text = text;
    this.foreground = foreground;
    this.font = font;
  }

  public String getText() {
    return text;
  }

  public void setText(String text) {
    this.text = text;
  }

  public Color getBackground() {
    return background;
  }

  public void setBackground(Color background) {
    this.background = background;
  }

  public Color getForeground() {
    return foreground;
  }

  public void setForeground(Color foreground) {
    this.foreground = foreground;
  }

  public Font getFont() {
    return font;
  }

  public void setFont(Font font) {
    this.font = font;
  }

  @Override
  public String toString() {
    return "DecoratedText{" + "text=" + text + ", background=" + background
           + ", foreground=" + foreground + ", font=" + font + "}";
  }

  public SimpleAttributeSet getAttributeSet(JTextPane textPane) {
    SimpleAttributeSet attrSet = new SimpleAttributeSet();
    if (getBackground() != null) {
      StyleConstants.setBackground(attrSet, getBackground());
    } else {
      StyleConstants.setBackground(attrSet, textPane.getBackground());
    }
    if (getForeground() != null) {
      StyleConstants.setForeground(attrSet, getForeground());
    } else {
      StyleConstants.setForeground(attrSet, textPane.getForeground());
    }
    Font font;
    if (getFont() != null) {
      font = getFont();
    } else {
      font = textPane.getFont();
    }
    StyleConstants.setFontFamily(attrSet, font.getFamily());
    StyleConstants.setItalic(attrSet, font.isItalic());
    StyleConstants.setBold(attrSet, font.isBold());
    StyleConstants.setFontSize(attrSet, font.getSize());
    return attrSet;
  }
}

class CustomTreeCellRenderer extends JPanel implements TreeCellRenderer {
  private DefaultTreeCellRenderer renderer = new DefaultTreeCellRenderer();
  private final JLabel icon = new JLabel();
  private final JTextPane textPane = new JTextPane();

  protected CustomTreeCellRenderer() {
    super(new BorderLayout());
    textPane.setContentType("text/html");
    textPane.setEditable(false);
    textPane.setOpaque(false);
    icon.setOpaque(false);
    setOpaque(false);
    add(icon, BorderLayout.WEST);
    add(textPane);
  }
  @Override public Component getTreeCellRendererComponent(
      JTree tree, Object value, boolean selected, boolean expanded,
      boolean leaf, int row, boolean hasFocus) {
    JLabel l = (JLabel) renderer.getTreeCellRendererComponent(
        tree, value, selected, expanded, leaf, row, hasFocus);

    Color bgColor;
    Color fgColor;
    if (selected) {
      bgColor = renderer.getBackgroundSelectionColor();
      fgColor = renderer.getTextSelectionColor();
    } else {
      bgColor = Optional.ofNullable(renderer.getBackgroundNonSelectionColor())
        .orElse(renderer.getBackground());
      fgColor = Optional.ofNullable(renderer.getTextNonSelectionColor())
        .orElse(renderer.getForeground());
    }

    UIDefaults defaults = new UIDefaults();
    defaults.put("TextPane[Enabled].backgroundPainter", bgColor);
    textPane.putClientProperty("Nimbus.Overrides", defaults);
    textPane.putClientProperty("Nimbus.Overrides.InheritDefaults", true);
    textPane.setBackground(bgColor);
    textPane.setForeground(fgColor);

    DefaultMutableTreeNode node = (DefaultMutableTreeNode) value;
    Object object = node.getUserObject();
    textPane.setText("");
    Document doc = textPane.getStyledDocument();
    if (object instanceof DecoratedText) {
      DecoratedText decText = (DecoratedText) object;
      try {
        doc.insertString(doc.getLength(), decText.getText(), decText.getAttributeSet(textPane));
      } catch (BadLocationException ex) {
        ex.printStackTrace();
      }
    } else if (object instanceof DecoratedText[]) {
      DecoratedText[] arrayDecText = (DecoratedText[]) object;
      for (DecoratedText decText : arrayDecText) {
        try {
          doc.insertString(doc.getLength(), decText.getText(), decText.getAttributeSet(textPane));
        } catch (BadLocationException ex) {
          ex.printStackTrace();
        }
      }
    } else {
      textPane.setText(Objects.toString(value));
    }

    icon.setIcon(l.getIcon());
    icon.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, l.getIconTextGap()));

    return this;
  }
  @Override public void updateUI() {
    super.updateUI();
    renderer = new DefaultTreeCellRenderer();
  }
}


来源:https://stackoverflow.com/questions/51913716/proper-manner-create-class-jtree-defaulttreecellrenderer-using-jtextpane

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!