最近在關注如何將SWT TreeViewer進行排序的動作,發現有個網友提到這個網站有相關範例
https://www.ibm.com/developerworks/lotus/library/expeditor-swt/
查了一下Sorting trees真的有存在,而這個範例所針對的為Tree,若是Tree本身的話也許真的
就要自行去將同一層的TreeItem Array做sorting,之後再依新的順序重新建置,並且再dispose
掉舊的部分!
在這邊主要探討的是,如何改寫這個範例變成由Recursive來進行建置新的TreeItem或排序,如
此一來即使Tree example新增至多層的結構(範例為三層),也並不需要修改排序及建置的code!
相關程式說明如下:
1. Sorting.java主程式不變
2. SortTreeListener.java修改sortTree method部分
在這method內,原則上相關的變數,如column數量及當下columnIndex是哪一個皆不變,但
這邊有新增判斷點擊header時,到底當下為1 or -1,目的乃是在排序時要進行遞增or遞減計算
而部分變數也宣告為全域變數
再來是說明新增的method - doSort來進行排序動作
首先從tree(root)進入,傳進去的第三個參數為其子項目(TreeItem[]),此時會先判斷TreeItem[]
本身是否存在及是否擁有子項目,若沒有的話則進行return
再來是進行排序TreeItem[]的動作,在Comparator內重新定義compare method規則,判斷這兩
筆TreeItem的text為String或double來對應計算。特別要注意的是olditem變數乃是判斷,假設
- node1
+ node1_1
- node1_2
- node1_2_1
- node1_2_2
node1_1本身當下是沒有被expanded的,那麼即使它可能有子項目也不針對它們進行排序的
動作! 但反之,如果像node1_2的話就會針對他的children進行排序了!
最後,就是進行TreeItem[]的走訪,目的是建立新的TreeItem[0] or TreeItem[1]...等等
如此一來在tree的第一層節點會重新排列,並且重新setText的節點名稱
但在第一層的第一個節點建立好之後,我們並不知道它是否還有children,因此再次進入
doSort method,並且傳入的參數分別為(新節點, 舊節點, 舊節點的children array)
此時會再次回到doSort的開頭....又重複了上面的說明
這邊要特別講的是帶入舊節點的目的 - oldItem
因為新節點當下還沒有綁定任何的children,因此只能透過舊節點得知是否有被expanded
而最後哪時要做dispose的動作,這得當所有的項目都建立好之後,才可以進行,否則項目
該有的children會消失,在還沒有建立完新節點之前! 因此時機點是在進入doSort的第一個
參數為Tree的當下!
DEMO
當下先展開TreeItem1,點擊TreeColumn1後進行由下往上遞減的排序
再來多展開TreeItem0,點擊TreeColumn1後進行由上往下遞減的排序
總結
1. 程式中的部分method為沿用本來版本的code,因此在這邊不列出
如:findColumnIndex, getColumnValues
2. 本來的範例只會進行第一層項目的排序,在此加入子項目也會一起排序,前提是它也有
被展開的情形下!
https://www.ibm.com/developerworks/lotus/library/expeditor-swt/
查了一下Sorting trees真的有存在,而這個範例所針對的為Tree,若是Tree本身的話也許真的
就要自行去將同一層的TreeItem Array做sorting,之後再依新的順序重新建置,並且再dispose
掉舊的部分!
在這邊主要探討的是,如何改寫這個範例變成由Recursive來進行建置新的TreeItem或排序,如
此一來即使Tree example新增至多層的結構(範例為三層),也並不需要修改排序及建置的code!
相關程式說明如下:
1. Sorting.java主程式不變
2. SortTreeListener.java修改sortTree method部分
private int columnIndex = 0;
private String sortColumn = "";
private int direction = 1;
private int numOfColumns;
private void sortTree(SelectionEvent e) {
TreeColumn column = (TreeColumn) e.widget;
Tree tree = column.getParent();
tree.setSortColumn(column);
TreeColumn sortColumn = tree.getSortColumn();
TreeColumn columns[] = tree.getColumns();
this.numOfColumns = columns.length;
this.sortIndex = this.findColumnIndex(columns, column, numOfColumns);
this.direction = sortColumn.getText().equals(this.sortColumn) ? -1*direction : direction;
this.sortColumn = sortColumn.getText();
tree.setSortDirection(direction == 1 ? SWT.UP : SWT.DOWN);
doSort(tree);
}
在這method內,原則上相關的變數,如column數量及當下columnIndex是哪一個皆不變,但
這邊有新增判斷點擊header時,到底當下為1 or -1,目的乃是在排序時要進行遞增or遞減計算
而部分變數也宣告為全域變數
再來是說明新增的method - doSort來進行排序動作
private void doSort(Tree tree){
doSort(tree, null, tree.getItems());
}
private void doSort(Object obj, TreeItem olditem, TreeItem treeItems[]){
boolean isTree = false;
//1. return condition
if(treeItems == null || (treeItems != null && treeItems.length == 0)){
return;
}
//2. sorting array
if(obj instanceof Tree || (olditem instanceof TreeItem && olditem.getExpanded())){
Arrays.sort(treeItems, new Comparator<TreeItem>(){
@Override
public int compare(TreeItem o1, TreeItem o2) {
// TODO Auto-generated method stub
String txt1 = o1.getText(columnIndex);
String txt2 = o2.getText(columnIndex);
if(NumberUtils.isCreatable(txt1))
return direction*((Double.parseDouble(txt1) - Double.parseDouble(txt2)) > 0 ? 1 : -1);
else
return direction*(txt1.compareToIgnoreCase(txt2) > 0 ? 1 : -1);
}
});
}
//3. create new TreeItem or doSort
for(TreeItem item : treeItems){
TreeItem nitem = null;
if(obj instanceof TreeItem){
nitem = new TreeItem((TreeItem)obj, SWT.NONE);
}else if(obj instanceof Tree){
nitem = new TreeItem((Tree)obj, SWT.NONE);
isTree = true;
}
nitem.setText(this.getColumnValues(item, numOfColumns));
doSort(nitem, item, item.getItems());
if(isTree){
item.dispose();
}
}
if(olditem != null){
((TreeItem)obj).setExpanded(olditem.getExpanded());
}
}
首先從tree(root)進入,傳進去的第三個參數為其子項目(TreeItem[]),此時會先判斷TreeItem[]
本身是否存在及是否擁有子項目,若沒有的話則進行return
再來是進行排序TreeItem[]的動作,在Comparator內重新定義compare method規則,判斷這兩
筆TreeItem的text為String或double來對應計算。特別要注意的是olditem變數乃是判斷,假設
- node1
+ node1_1
- node1_2
- node1_2_1
- node1_2_2
node1_1本身當下是沒有被expanded的,那麼即使它可能有子項目也不針對它們進行排序的
動作! 但反之,如果像node1_2的話就會針對他的children進行排序了!
最後,就是進行TreeItem[]的走訪,目的是建立新的TreeItem[0] or TreeItem[1]...等等
如此一來在tree的第一層節點會重新排列,並且重新setText的節點名稱
但在第一層的第一個節點建立好之後,我們並不知道它是否還有children,因此再次進入
doSort method,並且傳入的參數分別為(新節點, 舊節點, 舊節點的children array)
此時會再次回到doSort的開頭....又重複了上面的說明
這邊要特別講的是帶入舊節點的目的 - oldItem
因為新節點當下還沒有綁定任何的children,因此只能透過舊節點得知是否有被expanded
而最後哪時要做dispose的動作,這得當所有的項目都建立好之後,才可以進行,否則項目
該有的children會消失,在還沒有建立完新節點之前! 因此時機點是在進入doSort的第一個
參數為Tree的當下!
DEMO
當下先展開TreeItem1,點擊TreeColumn1後進行由下往上遞減的排序
總結
1. 程式中的部分method為沿用本來版本的code,因此在這邊不列出
如:findColumnIndex, getColumnValues
2. 本來的範例只會進行第一層項目的排序,在此加入子項目也會一起排序,前提是它也有
被展開的情形下!
留言
張貼留言