Color row in JTree

拥有回忆 提交于 2019-11-27 07:54:49

问题


I'd like to color elements in a JTree. However, simply adding a background color only to the label looks kind of strange. Particularly if more than one node is selected, the resulting shape looks ragged and distracting.

Is there a way to make the background extend the whole width of the tree element, so that the whole row gets colored? Either starting at the left border or starting at the beginning of the label, but definitely extending till the right border of the component?

Here is a small self-contained demo, based on this question.

import java.awt.*;
import javax.swing.*;
import javax.swing.tree.*;
public class SO26724913 {
    public static void main(String[] args) {
        DefaultMutableTreeNode a = new DefaultMutableTreeNode("a");
        DefaultMutableTreeNode b = new DefaultMutableTreeNode("b");
        DefaultMutableTreeNode c = new DefaultMutableTreeNode("c");
        a.add(b);
        a.add(c);
        final JTree tree = new JTree(a);
        tree.setCellRenderer(new DefaultTreeCellRenderer() {
                @Override
                public Component getTreeCellRendererComponent
                    (JTree tree, Object value, boolean selected,
                     boolean expanded, boolean leaf, int row, boolean focus)
                {
                    JComponent c = (JComponent)
                        super.getTreeCellRendererComponent
                        (tree, value, selected, expanded, leaf, row, focus);
                    DefaultMutableTreeNode node = (DefaultMutableTreeNode)value;
                    String data = (String)node.getUserObject();
                    if ("b".equals(data)) {
                        c.setBackground(Color.RED);
                        c.setOpaque(true);
                    }
                    else {
                        c.setBackground(null);
                        c.setOpaque(false);
                    }
                    return c;
                }
            });
        JFrame frm = new JFrame();
        frm.getContentPane().add(tree);
        frm.setSize(200, 200);
        frm.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frm.setVisible(true);
    }
}

This is what the code currently generates.

I'd prefer either this

or this.

回答1:


You might be able to override the paintComponent(Graphics) method of JTree to paint selection rectangles directly:

import java.awt.*;
import java.awt.event.*;
import java.util.Arrays;
import javax.swing.*;
import javax.swing.tree.*;

public class ColorTreeTest {
  private static final Color SELC = Color.RED;
  public JComponent makeUI() {
    FocusListener fl = new FocusListener() {
      @Override public void focusGained(FocusEvent e) {
        e.getComponent().repaint();
      }
      @Override public void focusLost(FocusEvent e) {
        e.getComponent().repaint();
      }
    };
    DefaultTreeCellRenderer r = new DefaultTreeCellRenderer() {
      @Override public Component getTreeCellRendererComponent(
          JTree tree, Object value, boolean selected, boolean expanded,
          boolean leaf, int row, boolean hasFocus) {
        JLabel l = (JLabel) super.getTreeCellRendererComponent(
            tree, value, selected, expanded, leaf, row, false);
        l.setBackground(selected ? Color.RED
                                 : tree.getBackground());
        l.setOpaque(true);
        return l;
      }
    };
    JPanel p = new JPanel(new GridLayout(1, 2));
    for (JTree t : Arrays.asList(new ColorTree1(), new ColorTree2())) {
      t.addFocusListener(fl);
      t.setCellRenderer(r);
      t.setOpaque(false);
      p.add(new JScrollPane(t));
    }
    return p;
  }
  static class ColorTree1 extends JTree {
    @Override public void paintComponent(Graphics g) {
      g.setColor(getBackground());
      g.fillRect(0, 0, getWidth(), getHeight());
      if (getSelectionCount() > 0) {
        g.setColor(SELC);
        for (int i : getSelectionRows()) {
          Rectangle r = getRowBounds(i);
          g.fillRect(r.x, r.y, getWidth() - r.x, r.height);
        }
      }
      super.paintComponent(g);
      if (getLeadSelectionPath() != null) {
        Rectangle r = getRowBounds(getRowForPath(getLeadSelectionPath()));
        g.setColor(hasFocus() ? SELC.darker() : SELC);
        g.drawRect(r.x, r.y, getWidth() - r.x - 1, r.height - 1);
      }
    }
  }
  static class ColorTree2 extends JTree {
    private static final Color SELC = Color.RED;
    @Override public void paintComponent(Graphics g) {
      g.setColor(getBackground());
      g.fillRect(0, 0, getWidth(), getHeight());
      if (getSelectionCount() > 0) {
        g.setColor(SELC);
        //@see http://ateraimemo.com/Swing/TreeRowSelection.html
        for (int i : getSelectionRows()) {
          Rectangle r = getRowBounds(i);
          g.fillRect(0, r.y, getWidth(), r.height);
        }
      }
      super.paintComponent(g);
      if (getLeadSelectionPath() != null) {
        Rectangle r = getRowBounds(getRowForPath(getLeadSelectionPath()));
        g.setColor(hasFocus() ? SELC.darker() : SELC);
        g.drawRect(0, r.y, getWidth() - 1, r.height - 1);
      }
    }
  }
  public static void main(String... args) {
    EventQueue.invokeLater(new Runnable() {
      @Override public void run() {
        createAndShowGUI();
      }
    });
  }
  public static void createAndShowGUI() {
    JFrame f = new JFrame();
    f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
    f.getContentPane().add(new ColorTreeTest().makeUI());
    f.setSize(320, 240);
    f.setLocationRelativeTo(null);
    f.setVisible(true);
  }
}


来源:https://stackoverflow.com/questions/26724913/color-row-in-jtree

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