[英]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.