民间,
我正在尝试创建渐变JTree控件。除了树单元格的背景不透明外,以下代码大部分都有效。如果有人打电话告诉我,我做得不对,我将不胜感激。
提前感谢您的帮助。
问候,
彼得
package TestPackage;
import javax.swing.*;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeCellRenderer;
import java.awt.*;
public class Test {
public Test() {
JFrame frame = new JFrame();
JPanel framePanel = new JPanel();
framePanel.setLayout(new BorderLayout());
frame.setContentPane(framePanel);
DefaultMutableTreeNode rootNode = new DefaultMutableTreeNode("Item");
DefaultMutableTreeNode childNode = new DefaultMutableTreeNode("Child");
rootNode.add(childNode);
GradientTree tree = new GradientTree(rootNode);
// JTree tree = new JTree(rootNode);
// tree.setBackground(Color.blue);
tree.setCellRenderer(new MyRenderer());
JScrollPane scroll = new JScrollPane(tree);
scroll.setOpaque(false);
framePanel.add(scroll, BorderLayout.CENTER);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new Test();
}
});
}
@SuppressWarnings("serial")
public static class GradientTree extends JTree {
public GradientTree(DefaultMutableTreeNode node) {
super(node);
}
@Override
protected void paintComponent(Graphics g) {
int h = getHeight();
int w = getWidth();
GradientPaint gradientPaint = new GradientPaint(0, 0, Color.LIGHT_GRAY, 0, h, Color.WHITE);
Graphics2D g2D = (Graphics2D) g;
g2D.setPaint(gradientPaint);
g2D.fillRect(0, 0, w, h);
this.setOpaque(false);
super.paintComponent(g);
this.setOpaque(true);
}
}
@SuppressWarnings({"serial" })
private class MyRenderer extends DefaultTreeCellRenderer {
public MyRenderer() {
this.setOpaque(false);
this.setForeground(Color.RED);
}
public Component getTreeCellRendererComponent(
JTree tree,
Object value,
boolean sel,
boolean expanded,
boolean leaf,
int row,
boolean hasFocus) {
super.getTreeCellRendererComponent(
tree, value, sel,
expanded, leaf, row,
hasFocus);
return this;
}
}
}
答案 0 :(得分:5)
这是一个真正的痛苦。 DefaultTreeCellRenderer
将忽略opaque
值并填写其内容。但是,你可以尝试一个标志。我过去做过,但没有时间测试它......
试试UIManager.put("Tree.rendererFillBackground", false)
。尝试在任何渲染器之前执行此操作,但在应用任何外观设置之后。
<强>已更新强>
在创建任何树之前设置此属性非常重要
没有|与...
public class TestTreeRenderer {
public static void main(String[] args) {
new TestTreeRenderer();
}
public TestTreeRenderer() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
JFrame frame = new JFrame("Test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new TreePane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TreePane extends JPanel {
private JTree tree;
public TreePane() {
// THIS IS VERY IMPORTANT
// You must set this BEFORE creating ANY trees!!
UIManager.put("Tree.rendererFillBackground", false);
setLayout(new BorderLayout());
tree = new JTree();
tree.setBackground(Color.BLUE);
System.out.println("Loading files...");
File root = new File("/etc");
DefaultMutableTreeNode rootNode = new DefaultMutableTreeNode(root.getName());
for (File file : root.listFiles()) {
rootNode.add(new DefaultMutableTreeNode(file.getName()));
}
System.out.println("Loading model");
DefaultTreeModel model = new DefaultTreeModel(rootNode);
tree.setModel(model);
add(new JScrollPane(tree));
}
}
}
答案 1 :(得分:2)
回答
(扩展@ Mad的回答,对基本问题的长期分析最终):
如果希望全局属性在手动设置到树的defaultTreeCellRenderer中有效,则该渲染器必须再次调用updateUI ,f.i。
UIManager.put("Tree.rendererFillBackground", false);
...
TreeCellRenderer r = new DefaultTreeCellRenderer() {
{
updateUI();
}
};
tree.setCellRenderer(r);
如果您不想要更改全局设置并且透明渲染器只有一些树实例 - 选项是
欺骗代码:
TreeCellRenderer r = new DefaultTreeCellRenderer() {
{
updateUI();
}
@Override
public void updateUI() {
Object old = UIManager.get("Tree.rendererFillBackground");
try {
UIManager.put("Tree.rendererFillBackground", false);
super.updateUI();
} finally {
UIManager.put("Tree.rendererFillBackground", old);
}
}
};
分析
从我的评论开始:
奇怪的是,仅仅设置CellRenderer(相对于让ui安装它的优点)会使旗帜无效
解决了这个难题:
DefaultTreeCellRenderer具有意图以从UIManager中的设置设置其fillBackground字段 - 但在实例化时失败。原因是 - 一个太常见的错误;-) - 实际上是在super的实例化中这样做,因为在super的构造函数中调用了一个重写的方法:
// this is implemented in DefaultTreeCellRenderer
// but called in JLabel constructor
public void updateUI() {
....
// we are in JLabel, that is fillBackground not yet known
fillBackground = DefaultLookup.getBoolean(this, ui, "Tree.rendererFillBackground", true);
...
}
然后在实例化过程中,字段值被硬编码:
private boolean fillBackground = true;
最终结果是(假设我们强制访问该字段,通过反射访问f.i.),无论UIManager中的设置如何,都会始终进行以下传递。
DefaultTreeCellRenderer renderer = new DefaultTreeRenderer();
assertTrue(renderer.fillBackground);
有了这个不寻常的东西:为什么 UIManager中的设置在让ui安装默认设置时有效?这里的原因是渲染器updateUI被调用两次:一次在实例化中,一次在树的updateUI中:
public void updateUI() {
setUI((TreeUI)UIManager.getUI(this));
// JW: at this point the renderer has its fillbackground hard-coded to true
SwingUtilities.updateRendererOrEditorUI(getCellRenderer());
// JW: now it's updateUI has been called again, and correctly set to the
// UIManager's value
SwingUtilities.updateRendererOrEditorUI(getCellEditor());
}
BTW:这个实例化混乱似乎是在jdk7中引入的......很可能(尽管没有检查)渲染器颜色的默认设置也不起作用。
答案 2 :(得分:0)
如何扩展DefaultTreeCellRenderer:
public class MyRenderer extends DefaultTreeCellRenderer {
public Component getTreeCellRendererComponent(JTree tree, Object value,
boolean isSelected, boolean expanded, boolean leaf, int row,
boolean hasFocus) {
JComponent c = (JComponent) super.getTreeCellRendererComponent(tree, value, isSelected, expanded, leaf, row, hasFocus);
c.setOpaque(true);
return c;
}
}
设置c.setOpaque(true);似乎解决了它。
答案 3 :(得分:0)
我真的很犹豫在这些Swing专家面前提出这个假设......但是最近的JDK能否真正纠正这个问题呢?
我的应用程序中有这样的代码,似乎工作得很好...... JTree的背景完美无瑕...... NB Jython,但应该是可以理解的:
def getTreeCellRendererComponent( self, tree, value, selected, expanded, leaf, row, has_focus ):
super_comp = self.super__getTreeCellRendererComponent( tree, value, selected, expanded, leaf, row, has_focus )
super_comp.opaque = not selected
...
Java版本是1.7.0_079