在this question中,我询问如何将JXTreeTable(SwingX)排序为其顶级元素。
我看了aephyr建议的库(mKorbel)并试图将它与JXTreeTable结合起来(我通过复制JXTreeTable的源代码创建了一个名为JXSortableTreeTable的新类)。 p>
到目前为止,我能够实现一种机制来对树表的节点进行排序,即当我的自定义排序器(见下文)的convertRowIndexToModel
被调用时,它返回的索引是正确的。
因此,我有一个看起来像这样的课程:
public class TreeTableRowSorter <M extends TreeTableModelAdapter> extends DefaultRowSorter {
private M treeTableModel; // model
private List<Integer> indices; // list where each entry is the model index
private IdentityHashMap<Object, NodeSorter> sorters;
private class IndicesMapFiller { // class that fills the "map" this.indices
public void fillIndicesMap(Object node) { // recursive
// Fills the indices "map"
}
}
@Override
public int convertRowIndexToModel(int index) {
return indices.get(index);
}
@Override
public int convertRowIndexToView(int index) {
return indices.indexOf(index);
}
@Override
public void toggleSortOrder(int columnIndex) {
sorters.get(treeTableModel.getRoot()).toggleSortOrder(columnIndex);
super.toggleSortOrder(columnIndex);
}
@Override
public void sort() {
getRowSorter(treeTableModel.getRoot()).sort(true);
indices = new ArrayList<Integer>();
for (int i = 0; i < getViewRowCount(); i++)
indices.add(-1);
IndicesMapFiller filler = new IndicesMapFiller(indices);
filler.fillIndicesMap(treeTableModel.getRoot());
System.out.println("INDICES: " + indices);
}
private class TreeTableRowSorterModelWrapper extends ModelWrapper<M, Integer> {
private final Object node;
private final TreeTableRowSorterModelWrapper parent;
public TreeTableRowSorterModelWrapper(Object node, TreeTableRowSorterModelWrapper parent) {
this.node = node;
this.parent = parent;
}
@Override
public M getModel() {
return treeTableModel;
}
@Override
public int getColumnCount() {
return (treeTableModel == null) ? 0 : treeTableModel.getColumnCount();
}
@Override
public int getRowCount() {
// Returns only the number of direct visible children in order for
// each NodeSorter to only sort its children (and not its children's
// children)
int rowCount = treeTableModel.getDirectVisibleChildrenCount(node, getParentPath());
return rowCount;
}
public TreePath getParentPath() {
Object root = treeTableModel.getRoot();
if (root == null || node == root)
return null;
if (parent.getNode() == root)
return new TreePath(root);
return parent.getParentPath().pathByAddingChild(parent);
}
@Override
public Object getValueAt(int row, int column) {
Object node = treeTableModel.getChild(getNode(), row);
return treeTableModel.getValue(node, column);
}
public Object getNode() {
return node;
}
}
public class NodeSorter extends DefaultRowSorter<M, Integer> {
private NodeSorter parent;
private Map<Object, NodeSorter> children;
public NodeSorter(Object root) {
this(null, root);
}
public NodeSorter(NodeSorter par, Object node) {
parent = par;
TreeTableRowSorterModelWrapper parentWrapper =
(parent == null) ? null : (TreeTableRowSorterModelWrapper) parent.getModelWrapper();
TreeTableRowSorterModelWrapper wrapper =
new TreeTableRowSorterModelWrapper(node, parentWrapper);
setModelWrapper(wrapper);
children = createChildren();
if (parent != null)
setMaxSortKeys(Integer.MAX_VALUE);
if (node == null)
return;
// Create the sorters for all children (even those not yet shown)
int childCount = getModel().getChildCount(node);
for (int i = 0; i < childCount; i++) {
Object childNode = getModel().getChild(node, i);
getChildSorter(childNode, sorters);
}
}
protected Map<Object, NodeSorter> createChildren() {
int childCount = getModel().getChildCount(getNode());
IdentityHashMap<Object, NodeSorter> map = new IdentityHashMap<Object, NodeSorter>(childCount);
return map;
}
public NodeSorter getParent() {
return parent;
}
TreeTableSortController<M> getMaster() {
return TreeTableSortController.this;
}
NodeSorter getChildSorter(Object node, Map<Object, NodeSorter> map) {
NodeSorter s = children.get(node);
if (s == null && map != null) {
s = new NodeSorter(this, node);
children.put(node, s);
map.put(node, s);
}
return s;
}
protected TreeTableRowSorterModelWrapper getTreeTableModelWrapper() {
return (TreeTableRowSorterModelWrapper) getModelWrapper();
}
public Object getNode() {
return ((TreeTableRowSorterModelWrapper) getModelWrapper()).getNode();
}
@Override
public void toggleSortOrder(int columnIndex) {
for (NodeSorter childSorter : children.values()) {
childSorter.toggleSortOrder(columnIndex);
}
super.toggleSortOrder(columnIndex);
}
private boolean firePathEvent = true;
void sort(boolean sortChildren) {
if (!isVisible())
return;
firePathEvent = false;
try {
super.sort();
} finally {
firePathEvent = true;
}
if (!sortChildren)
return;
for (NodeSorter sorter : children.values())
sorter.sort(sortChildren);
}
private TreePath getPathToRoot() {
if (parent == null)
return new TreePath(getNode());
return parent.getPathToRoot()
.pathByAddingChild(getNode());
}
}
如果模型数据的组织方式如此(最后一列中显示的模型中的每个全局节点的索引):
Name / Date / File UID | Glob. View Idx | Glob. Model Idx
(Root)
|- Mr. X / 1996/10/22 / AE123F6D | 0 | 0
|--- File1 / 2012/01/10 / DFC2345Q | 1 | 1
|--- File2 / 2012/01/11 / D321FEC6 | 2 | 2
|- Mrs. Y / 1975/03/03 / G2GF35EZ | 3 | 3
|--- File3 / 2012/02/29 / 35GERR32 | 4 | 4
|--- File4 / 2012/01/22 / LKJY2342 | 5 | 5
.
.
.
如果我对第二列进行排序,我想得到这个输出:
Name / Date / File UID | Glob. View Idx | Glob. Model Idx
(Root)
|- Mrs. Y / 1975/03/03 / G2GF35EZ | 0 | 3
|--- File4 / 2012/01/22 / LKJY2342 | 1 | 5
|--- File3 / 2012/02/29 / 35GERR32 | 2 | 4
|- Mr. X / 1996/10/22 / AE123F6D | 3 | 0
|--- File1 / 2012/01/10 / DFC2345Q | 4 | 1
|--- File2 / 2012/01/11 / D321FEC6 | 5 | 2
.
.
.
我实际获得的内容与非排序版本完全相同,只是convertRowIndexToModel的结果是正确的,因为如果我为模型的每一行调用它,我得到:
V -> M
0 -> 3
1 -> 5
2 -> 4
3 -> 0
4 -> 1
5 -> 2
我的问题归结为:
当继承DefaultRowSorter来实现像JXTreeTable这样的树表的排序时,我应该覆盖哪些方法? 由于我无法覆盖rowSorter(私有)的viewToModel或任何修改它的函数(也是私有),我实现了自己的V-&gt; M地图创建,并确保在调用我的分拣机的convertRowIndexTo(模型|视图)时使用它
我觉得在JXSortableTreeTable或者自定义排序器中的某个地方调用转换方法时会遗漏一些东西。
非常感谢您的帮助和富有洞察力的评论!
编辑&gt;在稍微测试一下结果后,它似乎与JXTreeTable的层次结构列相关,数据没有更新,因为它在其他列上排序时工作正常(我也尝试更改层次结构列(集合)到另一列)并且前者在它不再是分层时起作用了)
答案 0 :(得分:1)
基于aephyr库我已经签出,如果您修改这样的节点分类器,它应该只排序第一个元素:
public class NodeSorter extends DefaultRowSorter<M, Integer> {
[.....]
private Comparator noopComparator = new Comparator(){
@Override
public int compare(Object o1, Object o2) {
return 0;
}
};
@Override
public Comparator<?> getComparator(int column) {
// if it has no parent then compare --> sort
// if it has a parent then do nothing
if(parent != null)
return noopComparator;
Comparator<?> c = super.getComparator(column);
return c != null ? c : getMaster().getComparator(column);
}
[....]