【问题标题】:JTree is badly blurred when scrolling [closed]滚动时JTree严重模糊[关闭]
【发布时间】:2013-03-29 03:01:00
【问题描述】:

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

如果我做一些事情让它重新绘制,它会恢复正常,比如最小化和恢复窗口,或者在树中单击以使节点展开或折叠(但是如果我拖动窗口,模糊不会消失离开屏幕并返回,或将另一个窗口拖到它前面)。

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

我曾经从包含要显示的数据的数据结构中填充DefaultMutableTreeNodes,但是当节点数量很大(比如超过 10,000 个)时,这会导致性能问题。由于我拥有的数据已经在树形结构中,我意识到在不使用任何DefaultMutableTreeNodes 的情况下围绕它创建自定义 TreeModel 将相当简单。这使得 JTree 的填充速度更快,但现在我遇到了滚动模糊的问题。

下面的代码不是来自应用程序,但它可以按原样编译并演示问题。删除 tree.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();
         }
      });
   }
}

【问题讨论】:

  • 请编辑您的问题以包含一个 sscce 来展示您所描述的问题。
  • 某些地方不符合 Swing 的透明度要求。 IE。尝试将背景颜色设置为透明或半透明值
  • 移除 CustomCellRenderer 并覆盖 JTree.convertValueToText 后,仍然会出现同样的问题。
  • SSCCE 将花费大量时间 啊……换句话说:你的时间太宝贵了,我们的 即使发布不完整,也可以花时间解决您的问题? -1 并投票结束。
  • 我说如果必须要写SSCCE,看来我必须写了,所以我今天要写。但这需要很多时间。我不希望任何人花几个小时来为我解决这个问题,我只是希望以前遇到过这个问题的其他人能给我一个提示,告诉我出了什么问题,这样我就可以自己解决了。跨度>

标签: java swing jscrollpane jtree treemodel


【解决方案1】:

我怀疑你已经覆盖了paintComponent(),但忽略了super.paintComponent(g),如图here

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

编辑您的问题以包含 sscce 可能会澄清问题。

附录:作为参考,这是一个展示问题中看到的渲染工件的示例。

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

【讨论】:

  • 我没有在任何地方覆盖paintComponent。我覆盖了JTree.convertValueToText,因此它将为每个节点显示一个适当的字符串,而不是toString() 的默认功能,并且我覆盖了问题中提到的getTreeCellRendererComponent
  • 将视口滚动模式更改为 SIMPLE_SCROLL_MODE 阻止了模糊的发生(其他 2 种模式仍然有模糊)。但是当树很大时,当树被填充时,GUI 会冻结很长时间。我认为我的自定义 TreeModel 的 getIndexOfChild 需要改进性能,所以我会继续努力,看看会发生什么。
  • 虽然 SIMPLE_SCROLL_MODE 解决了滚动模糊问题,但现在它还有另一个问题,即在展开和折叠节点时有时无法正确刷新。但我想我已经找到了解决方案。今天下午的更多细节,包括 SSCCE。
  • 如果您将TreeCellRenderer 设置为不透明并绘制背景,您也许可以使用任何一种更有效的模式。
  • 看起来我的问题将通过透明单元格渲染器解决,但使用空颜色而不是 stackoverflow.com/questions/14563433/… 中的透明颜色
【解决方案2】:

解决方案:

  • 请勿使用setColorJTree 的背景更改为非透明颜色。

  • 为了节点的视觉透明度,实现自定义TreeCellRenderer 以为getBackgroundNonSelectionColorgetBackground 返回null,如JTree set background of node to non-opaque 中所述

    • JScrollPane 的视口模式设置为JViewport.SIMPLE_SCROLL_MODE 有助于解决滚动模糊问题,但不一定会重新绘制与展开和折叠 ndo 相关的问题。

【讨论】:

  • 只是为了澄清:a) 为 any 组件设置半透明背景需要将其 opacity 属性设置为 false,否则您将体验到绘画伪影。从技术上讲,这与@trashgod 怀疑的错误相同(覆盖paintComponent 而不调用super)b)DefaultTreeCellRenderer 有一个相当weird implementation regarding its background
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-07-22
  • 1970-01-01
  • 2015-02-06
  • 1970-01-01
  • 2022-12-09
  • 2012-03-03
相关资源
最近更新 更多