Java 滚动时,JTree严重模糊

Java 滚动时,JTree严重模糊,java,swing,jscrollpane,jtree,treemodel,Java,Swing,Jscrollpane,Jtree,Treemodel,我在JScrollPane中有一个JTree,当我使用滚动条时,树会变得模糊,如下图所示 如果我做了一些事情使其重新绘制,例如最小化并恢复窗口,或者在树中单击以使节点展开或折叠,则会恢复正常(但是,如果我将窗口从屏幕上向后拖动,或者在其前面拖动另一个窗口,则模糊不会消失) JTree有一个自定义的TreeModel和单元渲染器。最近的更改是针对TreeModel;单元渲染器已经存在很长一段时间,并且工作正常。单元呈现器是DefaultTreeCellRenderer的子类,仅覆盖gettreec

我在
JScrollPane
中有一个
JTree
,当我使用滚动条时,树会变得模糊,如下图所示

如果我做了一些事情使其重新绘制,例如最小化并恢复窗口,或者在树中单击以使节点展开或折叠,则会恢复正常(但是,如果我将窗口从屏幕上向后拖动,或者在其前面拖动另一个窗口,则模糊不会消失)

JTree有一个自定义的
TreeModel
和单元渲染器。最近的更改是针对
TreeModel
;单元渲染器已经存在很长一段时间,并且工作正常。单元呈现器是
DefaultTreeCellRenderer
的子类,仅覆盖
gettreecellrendercomponent
方法(以显示自定义图标)

我曾经从包含要显示的数据的数据结构中填充
DefaultMutableTreeNode
s,但是当节点数量很大(比如超过10000个)时,这会带来性能问题。由于我拥有的数据已经是一个树结构,因此我意识到在它周围创建一个自定义树模型将非常简单,而不需要使用任何
DefaultMutableTreeNode
s。这使得JTree的填充速度更快,但现在我只剩下这个模糊的滚动问题了

下面的代码不是来自应用程序,但它按原样编译并将演示问题。删除
树。setBackground
行可停止模糊行为

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();
         }
      });
   }
}
包堆栈溢出;
导入javax.swing.event.TreeModelListener;
导入javax.swing.tree.TreeModel;
导入javax.swing.tree.TreePath;
导入javax.swing.*;
导入java.awt.Color;
公共类NumberTreeModel实现TreeModel{
公共静态最终整数根数=100;
公共对象getChild(对象父对象,int索引){
收益指数;
}
public int getChildCount(对象节点){
返回isLeaf(节点)?0:根目录号;
}
@凌驾
public int getIndexOfChild(对象父对象、对象子对象){
int parentValue=((整数)parent).intValue();
int childValue=((整数)child.intValue();
返回parentValue==根目录号?childValue:-1;
}
公共对象getRoot(){
返回根用户号;
}
公共布尔isLeaf(对象节点){
返回((整数)节点).intValue()
我怀疑您重写了
paintComponent()
,但忽略了
super.paintComponent(g)
,如图所示

不太可能,您可以在滚动窗格的视口中尝试使用
setScrollMode()

编辑您的问题以包含一个选项可能会澄清问题

附录:作为参考,这里有一个示例没有显示问题中的渲染工件

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

导入java.awt.EventQueue;
导入javax.swing.JFrame;
导入javax.swing.JScrollPane;
导入javax.swing.JTree;
/**
*@见https://stackoverflow.com/a/15696825/230513
*/
公共级Sscce{
专用void display(){
JFrame f=新JFrame(“Sscce”);
f、 setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JTree树=新的JTree();
对于(int i=0;i
解决方案:

  • 不要使用
    setColor
    以非不透明颜色更改
    JTree
    的背景

  • 对于节点的可视透明性,请实现自定义的
    TreeCellRenderer
    ,以便为
    getBackgroundNonSelectionColor
    getBackground
    返回null,如中所述

    • JScrollPane
      的视口模式设置为
      JViewport。简单的滚动模式
      有助于解决滚动模糊问题,但不一定会在展开和折叠NDOE时重新绘制问题

我没有覆盖任何地方的
paintComponent
。我重写了
JTree.convertValueToText
,因此它将为每个节点显示一个适当的字符串,而不是默认的功能