這一篇將說明如何建構一TreeViewer UI,當點擊父節點時能夠自動pack相關文字至可顯示的
欄位大小;再來是說明如何達到autoExpand的效果,即自動指定展開哪一個父節點,可用在
初始化建立TreeViewer的當下自動展開之用。
由於展示的TreeViewer是建構在FormPage下面,因此會先說明如何設定FormPage相關的
extension,並且再追朔如何設定menu清單的項目,由此點擊item帶出頁面。
1. 建立plugin.xml的extension
建立menu
設定其extension
於點擊選項後,產生editor page,handler程式如下
設定其extension
2. 建立主頁面
editor page (MyFormEditor.java) 程式碼如下:
接下來才是實際的頁面內容(MyFormPage.java)
首先我們要提到的是createFormContent method,當您繼承FormPage時需定義之,您自訂的元
件可以在此建立。在此主要會以建立TreeViewer來說明之。
#設定資料來源 => setInput
在此先說明treeviewer的資料來源,當呼叫getResource時會針對Eclipse根目錄下的treeviewer
資料夾進行Filter,針對dirFilter部分若要深入到commons.properties那一層的話需要滿足在
ABC時上一層為treeviewer,而在ABC-123-321-555時上一層目錄名稱與其本身名稱開頭相等
。取得目錄的Filter之後,接下來就是過濾是否有檔案commons.properties檔案
D:\eclipse_mars\treeviewer\ABC\ABC-123-321-555\commons.properties
D:\eclipse_mars\treeviewer\DEF\DEF-456-8888\commons.properties
若皆符合的話
就會得到commons.properties本身,取其getParentFile即為
+ ABC-123-321-555
+ DEF-456-8888
再存至pFile陣列內
#建構treeviewer node => setContentProvider(new ViewContentProvider());
這個類別會進行的是將剛剛得到的資料進行某些行為定義
需要定義的method為
getElements
getChildren
getParent
hasChildren
getElements部分
一生成treeviewer時就會執行。主要為第一層節點資料,在此將剛剛的來源資料做走訪得到
其上一層目錄,如ABC-123-321-555 => ABC
並將此ABC, DEF存至Object[]後做回傳
getChildren部分
當點擊父節點時,就會觸發此method,此時就可以回傳該父節點實際目錄下的File resource
getParent部分
觸發時機點,當利用autoExpand時放置的element為某一子節點,如此就會觸發此method來
決定要回傳哪一個節點為此父節點
hasChildren部分
一生成treeviewer時就會執行。判斷父節點是否具備展開的資格,具備的話就會在其左邊
出現 > 的符號(若採用預設的圖示的情況下)
#定義treeviewer column及label顯示規則
呼叫以下method為建立column是否為pack及label的顯示規則
createColumn("NAME1", new ViewLabelProvider(true));
createColumn("NAME2", new ViewLabelProvider(false));
如在此會建立兩欄,分別為NAME1、NAME2
若為NAME2欄,在父節點部分該欄不顯示資料
#定義treeviewer TreeListener
主要目的為,點擊父節點展開的當下,自動pack因應可顯示內容的長度,調整column的寬
度;反之,當收起來時,自動pack當下已展開的內容長度。
需要提到的是,當展開tree時,若當下要自動調整欄寬的話,需要利用到asyncExec,否則
會無法達到調整的效果,因為您並不知道何時展開完成,因此也不知何時做調整欄寬。
DEMO
一開始只展示父節點
當點擊各父節點後,自動調整欄寬
補充
提完了本篇的重點autoPack之後,還有一個部分為autoExpand,重點只有一段code
還記得當我們在getResource時有針對treeMap put進各子類別的name map File resource
因此,當我們想要在一開始生成treeviewer時,自動展開某一父類別的話
可以呼叫expandToLevel,請注意第一個參數要放的是父類別的某一子類別的resource
在這一篇文章建構的tree為File type,因此放此對應的resource,treeviewer底層即會自動
幫你呼叫到setContentProvider類別定義的getParent()來取得父節點進而做展開的動作,若
回傳null則會無任何動靜!
欄位大小;再來是說明如何達到autoExpand的效果,即自動指定展開哪一個父節點,可用在
初始化建立TreeViewer的當下自動展開之用。
由於展示的TreeViewer是建構在FormPage下面,因此會先說明如何設定FormPage相關的
extension,並且再追朔如何設定menu清單的項目,由此點擊item帶出頁面。
1. 建立plugin.xml的extension
建立menu
設定其extension
menu
menu內的項目名稱,綁定的是command ID所命名的名稱
command ID
設定handler,點選項目後執行的程式,由command ID串連
於點擊選項後,產生editor page,handler程式如下
public class OpenMyProjectFormHandler extends AbstractHandler{
@Override
public Object execute(ExecutionEvent event) throws ExecutionException {
IWorkbenchWindow window = HandlerUtil.getActiveWorkbenchWindow(event);
String editorId = "com.bin.practice.ui.MyFormEditor";
try {
NullEditorInput input = new NullEditorInput();
IWorkbenchPage page = window.getActivePage();
page.openEditor(input, editorId, true, IWorkbenchPage.MATCH_ID);
} catch (PartInitException e) {
e.printStackTrace();
}
return null;
}
}
設定其extension
2. 建立主頁面
editor page (MyFormEditor.java) 程式碼如下:
public class MyFormEditor extends FormEditor{
@Override
protected void addPages() {
// TODO Auto-generated method stub
try {
this.addPage(new MyFormPage(this));
} catch (PartInitException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
@Override
public void doSave(IProgressMonitor monitor) {
// TODO Auto-generated method stub
}
@Override
public void doSaveAs() {
// TODO Auto-generated method stub
}
@Override
public boolean isSaveAsAllowed() {
// TODO Auto-generated method stub
return false;
}
}
接下來才是實際的頁面內容(MyFormPage.java)
public class MyFormPage extends FormPage{
private TreeViewer viewer;
private Tree tree;
private Map<String, File> treeMap;
public MyFormPage(FormEditor editor) {
this(editor, MyFormPage.class.getName(), "Name List");
}
protected void createFormContent(IManagedForm managedForm) {
ScrolledForm form = managedForm.getForm();
treeMap = new HashMap<String, File>();
Composite formBody = form.getBody();
Display display = formBody.getDisplay();
int numColumns = 2;
formBody.setLayout(new GridLayout(numColumns, false));
viewer = new TreeViewer(formBody, SWT.H_SCROLL | SWT.V_SCROLL | SWT.BORDER | SWT.FULL_SELECTION);
viewer.setContentProvider(new ViewContentProvider());
createColumn("NAME1", new ViewLabelProvider(true));
createColumn("NAME2", new ViewLabelProvider(false));
tree = viewer.getTree();
tree.setHeaderVisible(true);
tree.setLinesVisible(true);
GridData gd = new GridData(SWT.FILL, SWT.FILL, true, true, 1, 1);
tree.setLayoutData(gd);
File [] res = getResource();
viewer.setInput(res);
//ColumnViewerToolTipSupport.enableFor(viewer, ToolTip.NO_RECREATE);
//viewer.expandToLevel(treeMap.get("DEF-456-8888"), 1);
setPack();
viewer.addTreeListener(new ITreeViewerListener(){
@Override
public void treeCollapsed(TreeExpansionEvent event) {
// TODO Auto-generated method stub
File file = (File)event.getElement();
System.out.println(file.getName()+"....collapsed");
setAutoPack(display);
}
@Override
public void treeExpanded(TreeExpansionEvent event) {
// TODO Auto-generated method stub
File file = (File)event.getElement();
System.out.println(file.getName()+"....expanded");
setAutoPack(display);
}
});
form.pack();
}
}
首先我們要提到的是createFormContent method,當您繼承FormPage時需定義之,您自訂的元
件可以在此建立。在此主要會以建立TreeViewer來說明之。
#設定資料來源 => setInput
在此先說明treeviewer的資料來源,當呼叫getResource時會針對Eclipse根目錄下的treeviewer
資料夾進行Filter,針對dirFilter部分若要深入到commons.properties那一層的話需要滿足在
ABC時上一層為treeviewer,而在ABC-123-321-555時上一層目錄名稱與其本身名稱開頭相等
。取得目錄的Filter之後,接下來就是過濾是否有檔案commons.properties檔案
D:\eclipse_mars\treeviewer\ABC\ABC-123-321-555\commons.properties
D:\eclipse_mars\treeviewer\DEF\DEF-456-8888\commons.properties
若皆符合的話
就會得到commons.properties本身,取其getParentFile即為
+ ABC-123-321-555
+ DEF-456-8888
再存至pFile陣列內
private File[] getResource(){
final File directory = new File("treeviewer");
File[] pFile = null;
IOFileFilter dirFilter = new AbstractFileFilter() {
@Override
public boolean accept(File dir, String name) {
if(name.startsWith(dir.getName())) //confirm sub-directory start group name
return true;
else{
return dir.getName().startsWith(directory.getName()) && !name.startsWith(".");
}
}
};
IOFileFilter fileFilter = new NameFileFilter("commons.properties");
Collection<File> filters = FileUtils.listFiles(directory, fileFilter, dirFilter);
pFile = new File[filters.size()];
int i = 0;
for(File f : filters){
treeMap.put(f.getParentFile().getName(), f.getParentFile());
pFile[i++] = f.getParentFile();
}
return pFile;
}
#建構treeviewer node => setContentProvider(new ViewContentProvider());
這個類別會進行的是將剛剛得到的資料進行某些行為定義
需要定義的method為
getElements
getChildren
getParent
hasChildren
getElements部分
一生成treeviewer時就會執行。主要為第一層節點資料,在此將剛剛的來源資料做走訪得到
其上一層目錄,如ABC-123-321-555 => ABC
並將此ABC, DEF存至Object[]後做回傳
getChildren部分
當點擊父節點時,就會觸發此method,此時就可以回傳該父節點實際目錄下的File resource
getParent部分
觸發時機點,當利用autoExpand時放置的element為某一子節點,如此就會觸發此method來
決定要回傳哪一個節點為此父節點
hasChildren部分
一生成treeviewer時就會執行。判斷父節點是否具備展開的資格,具備的話就會在其左邊
出現 > 的符號(若採用預設的圖示的情況下)
class ViewContentProvider implements ITreeContentProvider {
public void inputChanged(Viewer v, Object oldInput, Object newInput) {
}
@Override
public void dispose() {
}
@Override
public Object[] getElements(Object inputElement) {
File[] sources = (File[]) inputElement;
File[] group = null;
File[] parents = new File[sources.length];
int i = 0;
for(File p : sources){
System.out.println("getElements..."+p);
parents[i++] = p.getParentFile();
}
Set<File> file_set = new HashSet<File>();
file_set.addAll(Arrays.asList(parents));
group = new File[file_set.size()];
i = 0;
for(File p : file_set){
group[i++] = p;
}
return group;
}
@Override
public Object[] getChildren(Object parentElement) {
System.out.println("getChildren..."+parentElement);
File file = (File) parentElement;
return file.listFiles();
}
@Override
public Object getParent(Object element) {
System.out.println("getParent..."+element);
File file = (File) element;
return file.getParentFile();
}
@Override
public boolean hasChildren(Object element) {
System.out.println("hasChildren..."+element);
File file = (File) element;
if (file.isDirectory()) {
File[] files = file.listFiles(new FilenameFilter() {
public boolean accept(File dir, String name) {
return name.equals("commons.properties");
}
});
return (files.length == 0) ? true : false;
}
return false;
}
}
#定義treeviewer column及label顯示規則
呼叫以下method為建立column是否為pack及label的顯示規則
createColumn("NAME1", new ViewLabelProvider(true));
createColumn("NAME2", new ViewLabelProvider(false));
如在此會建立兩欄,分別為NAME1、NAME2
若為NAME2欄,在父節點部分該欄不顯示資料
private void createColumn(String name, ColumnLabelProvider labelProvider){
TreeViewerColumn viewerColumn = new TreeViewerColumn(viewer, SWT.NONE);
TreeColumn column = viewerColumn.getColumn();
column.setText(name);
//column.setResizable(true);
viewerColumn.setLabelProvider(labelProvider);
}
class ViewLabelProvider extends ColumnLabelProvider {
private boolean showGroupName;
public ViewLabelProvider(boolean showGroupName){
this.showGroupName = showGroupName;
}
@Override
public String getText(Object element) {
if (element instanceof File) {
File file = (File) element;
if(file.getParentFile().getName().equals("treeviewer")){
if(this.showGroupName)
return getFileName(file);
else
return "";
}else{
return getFileName(file);
}
}
return null;
}
private String getFileName(File file) {
String name = file.getName();
return name.isEmpty() ? file.getPath() : name;
}
}
#定義treeviewer TreeListener
主要目的為,點擊父節點展開的當下,自動pack因應可顯示內容的長度,調整column的寬
度;反之,當收起來時,自動pack當下已展開的內容長度。
需要提到的是,當展開tree時,若當下要自動調整欄寬的話,需要利用到asyncExec,否則
會無法達到調整的效果,因為您並不知道何時展開完成,因此也不知何時做調整欄寬。
private void setAutoPack(Display display){
display.asyncExec(new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
setPack();
}
});
}
private void setPack(){
TreeColumn[] columns = tree.getColumns();
for (TreeColumn tableColumn : columns) {
tableColumn.pack();
}
}
DEMO
一開始只展示父節點
當點擊各父節點後,自動調整欄寬
補充
提完了本篇的重點autoPack之後,還有一個部分為autoExpand,重點只有一段code
viewer.expandToLevel(treeMap.get("DEF-456-8888"), 1);
還記得當我們在getResource時有針對treeMap put進各子類別的name map File resource
因此,當我們想要在一開始生成treeviewer時,自動展開某一父類別的話
可以呼叫expandToLevel,請注意第一個參數要放的是父類別的某一子類別的resource
在這一篇文章建構的tree為File type,因此放此對應的resource,treeviewer底層即會自動
幫你呼叫到setContentProvider類別定義的getParent()來取得父節點進而做展開的動作,若
回傳null則會無任何動靜!
留言
張貼留言