Swing/TreeRowSelection のバックアップの現在との差分(No.1)
TITLE:JTreeの行選択し、背景色を変更
Posted by aterai at 2011-01-17
JTreeの行選択し、背景色を変更
JTreeの行をクリックして選択し、行全体を選択色で描画します。-
category: swing
folder: TreeRowSelection
title: JTreeを行クリックで選択し、行全体を選択状態の背景色で描画
tags: [JTree, TreeCellRenderer, FocusListener]
author: aterai
pubdate: 2011-01-17T15:24:56+09:00
description: JTreeの行をクリックして選択し、行全体を選択状態の背景色で描画します。
image:
hreflang:
href: https://java-swing-tips.blogspot.com/2011/02/highlight-entire-jtree-row-on-selection.html lang: en
概要
JTree
の行をクリックして選択し、行全体を選択状態の背景色で描画します。
- &jnlp;
- &jar;
- &zip;
Screenshot
Advertisement
サンプルコード
#spanend
#spanadd
class RowSelectionTree extends JTree {
#spanend
private static final Color SELC = new Color(100, 150, 200);
private Handler handler;
#spandel
**サンプルコード [#adcacb20]
#spanend
#spandel
#code{{
#spanend
#spandel
final Color SELC = new Color(100,150,200);
#spanend
#spandel
JTree tree = new JTree() {
#spanend
@Override public void paintComponent(Graphics g) {
@Override protected void paintComponent(Graphics g) {
g.setColor(getBackground());
g.fillRect(0,0,getWidth(),getHeight());
if(getSelectionCount()>0) {
for(int i: getSelectionRows()) {
g.fillRect(0, 0, getWidth(), getHeight());
if (getSelectionCount() > 0) {
g.setColor(SELC);
for (int i : getSelectionRows()) {
Rectangle r = getRowBounds(i);
g.setColor(SELC);
g.fillRect(0, r.y, getWidth(), r.height);
}
}
super.paintComponent(g);
if(getLeadSelectionPath()!=null) {
if (getLeadSelectionPath() != null) {
Rectangle r = getRowBounds(getRowForPath(getLeadSelectionPath()));
g.setColor(SELC.darker());
g.drawRect(0, r.y, getWidth()-1, r.height-1);
g.setColor(hasFocus() ? SELC.darker() : SELC);
g.drawRect(0, r.y, getWidth() - 1, r.height - 1);
}
}
#spandel
};
#spanend
#spandel
tree.setUI(new javax.swing.plaf.basic.BasicTreeUI() {
#spanend
@Override public Rectangle getPathBounds(JTree tree, TreePath path) {
if(tree != null && treeState != null) {
return getPathBounds(path, tree.getInsets(), new Rectangle());
}
return null;
#spanadd
#spanend
@Override public void updateUI() {
removeFocusListener(handler);
super.updateUI();
setUI(new BasicTreeUI() {
@Override public Rectangle getPathBounds(JTree tree, TreePath path) {
if (tree != null && treeState != null) {
return getPathBounds(path, tree.getInsets(), new Rectangle());
}
return null;
}
#spanadd
#spanend
private Rectangle getPathBounds(
TreePath path, Insets insets, Rectangle bounds) {
Rectangle rect = treeState.getBounds(path, bounds);
if (rect != null) {
rect.width = tree.getWidth();
rect.y += insets.top;
}
return rect;
}
});
handler = new Handler();
addFocusListener(handler);
setCellRenderer(handler);
setOpaque(false);
}
private Rectangle getPathBounds(TreePath path, Insets insets, Rectangle bounds) {
bounds = treeState.getBounds(path, bounds);
if(bounds != null) {
bounds.width = tree.getWidth();
bounds.y += insets.top;
#spanadd
#spanend
static class Handler extends DefaultTreeCellRenderer implements FocusListener {
@Override public Component getTreeCellRendererComponent(
JTree tree, Object value, boolean selected, boolean expanded,
boolean leaf, int row, boolean hasFocus) {
JLabel l = (JLabel) super.getTreeCellRendererComponent(
tree, value, selected, expanded, leaf, row, hasFocus);
l.setBackground(selected ? SELC : tree.getBackground());
l.setOpaque(true);
return l;
}
return bounds;
#spanadd
#spanend
@Override public void focusGained(FocusEvent e) {
e.getComponent().repaint();
}
#spanadd
#spanend
@Override public void focusLost(FocusEvent e) {
e.getComponent().repaint();
}
}
#spandel
});
#spanend
#spandel
tree.setOpaque(false);
#spanend
#spanadd
}
#spanend
View in GitHub: Java, Kotlin解説
以下のような設定で、JTreeを行選択できるように変更し、表示もNimbus Look&Feel風に描画するようにしています。解説
- 左: デフォルト
-
MetalLookAndFeel
などでは選択でノードの背景色が変化
-
- 右:
JTree
ノードを行選択に変更-
NimbusLookAndFeel
風に行全体を選択状態の背景色で描画 -
BasicTreeUI#getPathBounds(...)
をオーバーライドしてノードではなく行のクリックで選択可能に変更- ドキュメントのBasicTreeUI (Java Platform SE 8)では「パスのコンポーネントのどれかが現在有効な場合は、
null
が返されます。(Will return null if any component in path is currently valid.
)」となっているがコードは無効な場合null
になる - [JDK-8281692] javadoc for getPathBounds() in TreeUI and BasicTreeUI is incorrect - Java Bug Systemによると
Java 19
でWill return null if any component in path is currently invalid.
と修正された
- ドキュメントのBasicTreeUI (Java Platform SE 8)では「パスのコンポーネントのどれかが現在有効な場合は、
-
JTree
の背景をsetOpaque(false)
で透明(非描画)に設定しJTree#paintComponent(...)
をオーバーライドして選択された行を背景色で描画 - 不透明にした
TreeCellRenderer
を使用してノードの選択色をJTree#paintComponent(...)
の背景色と同じものに変更 - 別コンポーネントにフォーカスが移動した場合
LeadSelection
のBorder
を描画しない(選択背景色で上書き)ように設定- デフォルトではノードのみ再描画されるので
FocusListener
を追加してJTree
全体を再描画 -
UIManager.put("Tree.repaintWholeRow", Boolean.TRUE)
を設定することでも回避可能
- デフォルトではノードのみ再描画されるので
-
- BasicTreeUI#getPathBounds(...)をオーバーライドして、ノードではなく、行のクリックで選択可能に変更
- JTreeをsetOpaque(false)で透明にし、JTree#paintComponent(...)をオーバーライドして選択された行を背景色で描画
- 不透明にしたTreeCellRendererを使用して、ノードの選択色をJTree#paintComponent(...)の背景色と同じものに変更
参考リンク
- JTable でセルのないところに行っぽい表示を出せますか? - KrdLab's blog
- Highlight a node's descendants in JTree - Santhosh Kumar's Weblog
- NimbusLookAndFeelでJTreeのセル選択を行全体ではなくノードに限定する
- こちらは逆に、
NimbusLookAndFeel
で行全体の選択を行わないようにする方法
- こちらは逆に、
- [JDK-8047749] javadoc for getPathBounds() in TreeUI and BasicTreeUI is incorrect - Java Bug System
- [JDK-8281692] javadoc for getPathBounds() in TreeUI and BasicTreeUI is incorrect - Java Bug System
- JTreeのノード選択可能な領域を行全体に拡張する