这篇小文是本系列( 第一部分 第二部分 )的最终章。主要说下与checkboxtreetable组件相关的几个hack技巧。
运行本demo
- 在本系列的第一部分下载 jxtreetable_with_checkbox.zip 到本地并解压。
- NetBeans主菜单依次选择“文件”——“打开项目”。
- 在弹出的“打开项目”对话框中选择刚才解压之后的jxtreetable_with_checkbox目录,点击“打开项目”按钮。
- 在附件中下载TestFrame3.zip解压为TestFrame3.java放到cn.vearn.checktreetable包下。
- 在附件中下载CheckTreeTableManager2.zip解压为CheckTreeTableManager2.java放到org.jdesktop.swingx.ux包下。
- “项目”视图选中TestFrame3,按Shift + F6运行文件。
- 点击“显示highlighter”复选按钮,可以切换是否Highlighter。
- 点击“禁止列交换”复选按钮,可以切换是否允许通过鼠标拖拽进行列交换。
#1 设置Highlighter
swingx中的Highlighter内容很丰富,不过在这里只是简单地对奇偶行用不同背景色。实现这个很简单:
checkbox1 = new JCheckBox("显示highlighter");
checkbox1.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
treetable.setHighlighters(checkbox1.isSelected() ? HighlighterFactory.createSimpleStriping() : null);
}
});
效果是这个样子的:
#2 禁止列交换
JTable有这样一个特性:通过鼠标拖拽表头中某一列可以对列进行交换。checkboxtreetable也继承了这个特性。不过这导致了一个问题,如果将包含JTree的第一列交换后(见下图),我们无法通过点击树节点之前的checkbox来改变选中状态了。这是由于CheckTreeTableManager通过监听mouseClicked事件来判断鼠标点击坐标,来选中树节点之前的checkbox,交换列之后改变了坐标位置,导致不能改变树节点之前的checkbox。
解决方法也很简单,禁止列交换就可以了:
checkbox2 = new JCheckBox("禁止列交换");
checkbox2.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
treetable.getTableHeader().setReorderingAllowed(checkbox2.isSelected() ? false : true);
}
});
要是希望含JTree的第一列固定,其他列可以交换可以吗?可以的,不过有点麻烦:
treetable = new JXTreeTable(new TestTreeTableModel(createDummyData())) {
protected JTableHeader createDefaultTableHeader() {
return new JTableHeader(columnModel) {
@Override
public void setDraggedColumn(TableColumn aColumn) {
if (aColumn == getColumnModel().getColumn(0)) {
return;
}
super.setDraggedColumn(aColumn);
}
};
}
protected TableColumnModel createDefaultColumnModel() {
return new DefaultTableColumnModel() {
public void moveColumn(int columnIndex, int newIndex) {
if (columnIndex == 0 || newIndex == 0) {
return;
}
super.moveColumn(columnIndex, newIndex);
}
};
}
}; // JXTreeTable构造方法
#3 更换CheckTreeTableManager
在#2中我们已经发现一个问题,也就是CheckTreeTableManager实际上是以一种hack手段(判断点击坐标位置)来改变checkbox的状态。那么我们换一种方式来实现,通过选中一行(或多行)来选中树节点前的checkbox,用TreeSelectionListener来监听用户事件:
public void valueChanged(TreeSelectionEvent e) {
TreePath path = e.getPath();
...
}
获得TreePath的引用之后,就和之前的实现一样了。不过这种方式也带来了几个问题:
- 选中chechbox的行为比较怪异,其他UI库中的checkboxtreetable都是通过点击树节点前的checkbox来改变其状态。
- 只要在某一行点击,就会改变checkbox状态,容易误操作。
- 先选中一个树节点的checkbox,如果想取消选中,需要按住Ctrl在取消选中该行(Windows环境下),很麻烦。
CheckTreeTableManager和CheckTreeTableManager2究竟如何选择,看您了。
后记
虽然swing在国内比较冷清,但我还是尽力写好这个系列。是santhosh 的文章帮助我在项目中用上了checkboxtreetable,那么我也希望对社区做一些贡献。能帮上一个人少走些弯路,目的就达到了。本系列至此全部结束,谢谢大家!