JTree сильно размыт при прокрутке

У меня есть JTree внутри JScrollPaneи когда я использую полосу прокрутки, дерево становится размытым, как вы можете видеть на изображении ниже.

Он возвращается в нормальное состояние, если я делаю что-то, чтобы заставить его перекрашиваться, например сворачиваю и восстанавливаю окно, или щелкаю по дереву, чтобы узел расширялся или сворачивался (однако размытие не исчезает, если я перетаскиваю окно за пределы экрана и обратно, или перетащите другое окно перед ним).

У JTree есть обычай TreeModel и рендерер клеток. Недавнее изменение было для TreeModel; клеточный рендерер был там долгое время и работал нормально. Ячейка рендеринга является подклассом DefaultTreeCellRendererтолько с getTreeCellRendererComponent переопределенный метод (для отображения пользовательских значков).

Я привык заселять DefaultMutableTreeNodeиз структуры данных, которая содержала данные для отображения, но это создавало проблемы с производительностью, когда число узлов было большим (например, более 10000). Поскольку данные, которые у меня были, уже были в древовидной структуре, я понял, что было бы довольно просто создать вокруг них собственную TreeModel без использования каких-либо DefaultMutableTreeNodes. Это заставило JTree заполняться быстрее, но теперь у меня осталась проблема размытой прокрутки.

Размытые JTree

Приведенный ниже код не из приложения, но он компилируется как есть и продемонстрирует проблему. Удаление tree.setBackground линия останавливает размытое поведение.

package stackru;

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

2 ответа

Решение

Решение:

  • Не использовать setColor изменить фон JTree с непрозрачным цветом.

  • Для визуальной прозрачности узлов, реализовать пользовательский TreeCellRenderer вернуть ноль для getBackgroundNonSelectionColor а также getBackground, как описано в JTree, установить фон узла как непрозрачный

    • установка режима просмотра JScrollPane в JViewport.SIMPLE_SCROLL_MODE помогает справиться с проблемой размытия прокрутки, но не обязательно перерисовывает проблемы с разворачивающимися и сворачивающимися окнами.

Я подозреваю, что вы изменили paintComponent() но пренебречь super.paintComponent(g), как показано здесь.

Менее вероятно, вы могли бы поэкспериментировать с setScrollMode() в области просмотра панели прокрутки.

Редактирование вашего вопроса для включения sscce может решить проблему.

Приложение: Для справки, вот пример, который не демонстрирует артефакт рендеринга, видимый в вопросе.

введите описание изображения здесь

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

/**
 * @see https://stackru.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();
            }
        });
    }
}
Другие вопросы по тегам