swing tree checkbox

本文介绍如何在Swing的树节点(Tree Node)上显示Checkbox,并实现跟随Look and Feel变化的功能。通过继承DefaultTreeCellRenderer并自定义渲染器,文章详细展示了如何利用JCheckBox的渲染效果来定制树节点图标。
swing标准库,实在有些简陋,很多显然的需求却无法满足,jdk5以前的版本,连表格列的排序功能都没有,swing最大的毛病也在这。最近学习python,同时也学习了一些GUI库,发现基本上tree都支持多列显示,在swing里,你就必须找第三方库了。

废话不说了,还是说说本来的需求。
我是需要在tree的node上显示checkbox。要满足这个需求,最明显的就有两个方法。
1 实现TreeCellRenderer接口,JCheckBox来做渲染,这样就可以,不过这有个问题,就是感观上和默认node实现,有很多差异,一些如选中,焦点,背景色等等,这些在DefaultTreeCellRenderer之类里有很多关于此类的考虑,如果自己再考虑,写一遍,似乎不合适。

2 用icon图片来代替,这是个方法,但是我有个期望是,希望checkbox能跟随look&feel做切换,所以期望是系统采用各个look&feel自己的chekbox。

大家知道,swing是自己画的,这样的话,那么icon也是,也就是说,我可以借用JCheckBox的渲染来渲染treenode的icon。最初想法是,直接用JCheckBox的icon放到DefaultTreeCellRenderer的icon里,但却报错,原因是DefaultTreeCellRenderer父类是JLabel,每个组件的icon的渲染,与组件相关的model是紧密联系的。

void paintIcon(Component c, Graphics g, int x, int y);


不同组件的icon不能直接使用。那么怎么办呢?其实也很简单,保证paintIcon的Component参数与icon一致就行了。

具体代码:

public class CheckboxTreeNodeRenderer extends DefaultTreeCellRenderer implements
TreeCellRenderer {

private static final long serialVersionUID = 1L;

private JCheckBox checkbox = new JCheckBox();

private Icon checkboxIcon = UIManager.getIcon("CheckBox.icon");

private ProxyCheckBoxIcon proxyIcon = new ProxyCheckBoxIcon();

private Font normal;

private Font disabled;

@SuppressWarnings("unchecked")
public CheckboxTreeNodeRenderer() {
normal = getFont().deriveFont(Font.PLAIN);
Map<TextAttribute, Object> attrs = (Map<TextAttribute, Object>) normal.getAttributes();
attrs.put(TextAttribute.STRIKETHROUGH, TextAttribute.STRIKETHROUGH_ON);
//attrs.put(TextAttribute.FONT, getFont().deriveFont(Font.ITALIC));
disabled = getFont().deriveFont(attrs);
}

public Component getTreeCellRendererComponent(JTree tree, Object value,
boolean selected, boolean expanded, boolean leaf, int row,
boolean hasFocus) {
super.getTreeCellRendererComponent(tree, value, selected, expanded,
leaf, row, hasFocus);
if (value instanceof CheckboxTreeNode) {
CheckboxTreeNode ctn = (CheckboxTreeNode) value;
checkbox.setSelected(ctn.isChecked());
setIcon(proxyIcon);
if (ctn.isChecked()) {
setFont(disabled);
if (!selected)
setForeground(Color.GRAY);
} else {
setFont(normal);
//setForeground(Color.BLACK);
}
} else {
setFont(normal);
}
return this;
}

private class ProxyCheckBoxIcon implements Icon, Serializable {

private static final long serialVersionUID = 1L;

@Override
public void paintIcon(Component c, Graphics g, int x, int y) {
checkboxIcon.paintIcon(checkbox, g, x, y);
}

@Override
public int getIconWidth() {
return checkboxIcon.getIconWidth();
}

@Override
public int getIconHeight() {
return checkboxIcon.getIconHeight();
}

}

}


以上代码除了实现checbox外,还实现了选中时,把显示文字增加删除线。(反正没找到简单方法,但在QT里很简单)。

下面是选中节点的判断监听类:

public class CheckboxNodeCheckedListener extends MouseAdapter implements MouseListener {

@Override
public void mousePressed(MouseEvent e) {
JTree tree = (JTree) e.getSource();
TreePath clickedPath = tree.getPathForLocation(e.getX(), e.getY());

if (e.getClickCount() == 1) {

if (clickedPath != null && !tree.isEditing()) {
Object node = clickedPath.getLastPathComponent();

if (node instanceof CheckboxTreeNode) {
CheckboxTreeNode treeNode = (CheckboxTreeNode) node;
DefaultTreeModel model = (DefaultTreeModel) tree.getModel();

TreeNode[] currPath = model.getPathToRoot(treeNode);
Rectangle rec = tree.getPathBounds(new TreePath(currPath));

if (e.getX() - rec.getX() <= 13) { // 默认为 13x13大小
treeNode.setChecked(!treeNode.isChecked());
model.nodeChanged(treeNode);
}
}
}
}
}
}
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值