JTree сильно размыт при прокрутке
У меня есть JTree
внутри JScrollPane
и когда я использую полосу прокрутки, дерево становится размытым, как вы можете видеть на изображении ниже.
Он возвращается в нормальное состояние, если я делаю что-то, чтобы заставить его перекрашиваться, например сворачиваю и восстанавливаю окно, или щелкаю по дереву, чтобы узел расширялся или сворачивался (однако размытие не исчезает, если я перетаскиваю окно за пределы экрана и обратно, или перетащите другое окно перед ним).
У JTree есть обычай TreeModel
и рендерер клеток. Недавнее изменение было для TreeModel
; клеточный рендерер был там долгое время и работал нормально. Ячейка рендеринга является подклассом DefaultTreeCellRenderer
только с getTreeCellRendererComponent
переопределенный метод (для отображения пользовательских значков).
Я привык заселять DefaultMutableTreeNode
из структуры данных, которая содержала данные для отображения, но это создавало проблемы с производительностью, когда число узлов было большим (например, более 10000). Поскольку данные, которые у меня были, уже были в древовидной структуре, я понял, что было бы довольно просто создать вокруг них собственную TreeModel без использования каких-либо DefaultMutableTreeNode
s. Это заставило 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();
}
});
}
}