[英]How to set transparent background for JTree cell?
民间,
我正在尝试创建一个渐变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;
}
}
}
这是一个真正的痛苦。 DefaultTreeCellRenderer
将忽略opaque
值,并DefaultTreeCellRenderer
填充其内容。 但是,有一个标志可以尝试。 我过去做过,但是没有时间进行测试...
尝试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));
}
}
}
回答
(扩展@Mad的答案,对基本问题的冗长分析在最后):
如果要使global属性在手动设置为树的defaultTreeCellRenderer中生效,则该渲染器必须再次调用updateUI,
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;
最终结果是(假设我们通过反射强制访问该字段),无论UIManager中的设置如何,始终执行以下操作。
DefaultTreeCellRenderer renderer = new DefaultTreeRenderer();
assertTrue(renderer.fillBackground);
与此不同寻常的是:为什么让UI安装默认设置时,UIManager 中的设置会生效? 这是因为渲染器的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());
}
顺便说一句:这种实例化混乱似乎是在jdk7中引入的...很可能(虽然没有检查)渲染器颜色的默认设置也不起作用。
如何像这样扩展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); 似乎解决了。
在这些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
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.