Question

I have a JTree inside a JScrollPane, and when I use the scrollbar the tree gets all blurred up, as you can see in the image below.

It gets back to normal if I do something to make it repaint, like minimize and restore the window, or click in the tree to make a node expand or collapse (however the blurring doesn't go away if I drag the window off the screen and back, or drag another window in front of it).

The JTree has a custom TreeModel and cell renderer. The recent change was for the TreeModel; the cell renderer has been there for a long time and was working fine. The cell renderer is a subclass of DefaultTreeCellRenderer, with only the getTreeCellRendererComponent method overridden (to display custom icons).

I used to populate DefaultMutableTreeNodes from a data structure which contained the data to be displayed, but that was giving performance problems when the number of nodes was large (like over 10,000). Since the data I had was already in a tree structure, I realized it would be fairly simple to create a custom TreeModel around it without using any DefaultMutableTreeNodes. That made the JTree populate more quickly, but now I'm left with this blurred scrolling problem.

Blurred JTree

The code below isn't from the application, but it compiles as is and will demonstrate the problem. Removing the tree.setBackground line stops the blurry behavior.

package stackoverflow;

import javax.swing.event.TreeModelListener;
import javax.swing.tree.TreeModel;
import javax.swing.tree.TreePath;
import javax.swing.*;
import java.awt.Color;


public class NumberTreeModel implements TreeModel {

   public static final int ROOT_NUMBER = 100;

   public Object getChild(Object parent, int index) {
      return index;
   }

   public int getChildCount(Object node) {
      return isLeaf(node) ? 0 : ROOT_NUMBER;
   }

   @Override
   public int getIndexOfChild(Object parent, Object child) {
      int parentValue = ((Integer) parent).intValue();
      int childValue = ((Integer) child).intValue();
      return parentValue == ROOT_NUMBER ? childValue : -1 ;
   }

   public Object getRoot() {
      return ROOT_NUMBER;
   }

   public boolean isLeaf(Object node) {
      return ((Integer) node).intValue() < ROOT_NUMBER;
   }

   public void addTreeModelListener(TreeModelListener listener) { }
   public void removeTreeModelListener(TreeModelListener listener) { }
   public void valueForPathChanged(TreePath path, Object obj) { }

   public static void display() {

      JFrame frame = new JFrame("Number JTree");
      frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      NumberTree tree = new NumberTree();
      tree.setModel(new NumberTreeModel());
      tree.setBackground(new Color(0,0,0,0));
      JScrollPane scroll = new JScrollPane(tree);
      frame.add(scroll);
      scroll.getViewport().setScrollMode(JViewport.BLIT_SCROLL_MODE);
      tree.expandRow(0);
      frame.pack();
      frame.setSize(300, 400);
      frame.setLocationRelativeTo(null);
      frame.setVisible(true);
   }

   public static class NumberTree extends JTree {
      static final long serialVersionUID = 1;

      @Override
      public String convertValueToText(Object value, boolean selected, boolean expanded, boolean leaf,
               int row, boolean hasFocus) {
         if (value instanceof Integer) {
            int n = ((Integer) value).intValue();
            return n + "=========".substring(0, n % 10);
         } else {
            System.out.println("value class=" + value.getClass());
            return value.toString();
         }
      }
   }

   public static void main(String[] args) {
      SwingUtilities.invokeLater(new Runnable() {
         public void run() {
            display();
         }
      });
   }
}
Was it helpful?

Solution 2

Solution:

  • Don't use setColor to change the background of the JTree with a non-opaque color.

  • For visual transparency of the nodes, implement a custom TreeCellRenderer to return null for getBackgroundNonSelectionColor and getBackground, as described in JTree set background of node to non-opaque

    • setting the viewport mode of the JScrollPane to JViewport.SIMPLE_SCROLL_MODE helps the scroll blur problem, but not necessarily repaint problems with expanding and collapsing ndoes.

OTHER TIPS

I suspect you have overridden paintComponent() but neglected super.paintComponent(g), as shown here.

Less likely, you might experiment with setScrollMode() in the scroll pane's viewport.

Editing your question to include an sscce might clarify the problem.

Addendum: For reference, here's an example that does not exhibit the rendering artifact seen in the question.

enter image description here

import java.awt.EventQueue;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTree;

/**
 * @see https://stackoverflow.com/a/15696825/230513
 */
public class Sscce {

    private void display() {
        JFrame f = new JFrame("Sscce");
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        JTree tree = new JTree();
        for (int i = 0; i < tree.getRowCount(); i++) {
            tree.expandRow(i);
        }
        f.add(new JScrollPane(tree));
        f.pack();
        f.setSize(200, 200);
        f.setLocationRelativeTo(null);
        f.setVisible(true);
    }

    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                new Sscce().display();
            }
        });
    }
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top