TreeViewer 是 Eclipse JFace 提供的強大樹形檢視組件,採用「內容提供器」與「標籤提供器」分離模型,靈活構建樹狀結構並控制節點顯示。本文將系統拆解其構建步驟、核心介面實作細節,並通過完整檔案瀏覽器範例演示實戰應用。
TreeViewer tv = new TreeViewer(composite);tv.setContentProvider(new FileTreeContentProvider());tv.setLabelProvider(new FileTreeLabelProvider());tv.setInput("root");(輸入物件將傳遞給內容提供器的 getElements 方法)內容提供器負責樹的資料結構與層級關係,需實作以下關鍵方法:
樹構建起始點,回傳根節點陣列。inputElement 即 setInput 傳入的物件。
判斷節點是否有子節點,回傳 true 時節點顯示展開圖示(+)。
使用者展開節點時呼叫,回傳該節點的直接子節點陣列。
回傳指定節點的父節點,支援向上導航。
輸入模型變更時觸發,可在此更新內部狀態或註冊監聽器。
Viewer 銷毀時呼叫,釋放資源(如取消監聽、關閉連線)。
實作重點:getElements、hasChildren、getChildren 是構建樹的三大核心。流程為:取得根 → 判斷是否有子節點 → 遞迴取得子節點。
class FileTreeContentProvider implements ITreeContentProvider {
public Object[] getChildren(Object arg0) {
return ((File) arg0).listFiles(); // 返回目錄下檔案/子目錄
}
public Object getParent(Object arg0) {
return ((File) arg0).getParentFile(); // 返回父目錄
}
public boolean hasChildren(Object arg0) {
Object[] obj = getChildren(arg0);
return obj != null && obj.length > 0; // 有子節點顯示 "+"
}
public Object[] getElements(Object arg0) {
System.out.println(arg0); // 輸入通常為 "root"
return File.listRoots(); // 以磁碟根目錄作為樹的根節點
}
public void dispose() {}
public void inputChanged(Viewer v, Object old, Object nw) {}
}
決定節點的文字與圖示。核心方法:
getText(Object obj):回傳節點顯示文字。getImage(Object obj):回傳節點圖示(Image 物件)。class FileTreeLabelProvider implements ILabelProvider {
private List listeners = new ArrayList();
private Image fileImg, dirImg;
boolean preserveCase;
public FileTreeLabelProvider() {
try {
fileImg = new Image(null, new FileInputStream("icons/file.gif"));
dirImg = new Image(null, new FileInputStream("icons/directory.gif"));
} catch (FileNotFoundException e) {}
}
public Image getImage(Object obj) {
return ((File) obj).isDirectory() ? dirImg : fileImg;
}
public String getText(Object obj) {
String text = ((File) obj).getName();
if (text.length() == 0) text = ((File) obj).getPath();
return preserveCase ? text : text.toUpperCase(); // 依核取方塊決定大小寫
}
// 標準監聽器管理與 dispose 略...
public void setPreserveCase(boolean preserveCase) {
this.preserveCase = preserveCase;
fireLabelProviderChanged(new LabelProviderChangedEvent(this));
}
}
整合上述提供器,建立可切換大小寫的檔案樹視窗。
public class FileBrowserTreeViewer extends ApplicationWindow {
public FileBrowserTreeViewer() { super(null); }
public void run() {
setBlockOnOpen(true);
open();
Display.getCurrent().dispose();
}
protected void configureShell(Shell shell) {
super.configureShell(shell);
shell.setText("File Tree");
shell.setSize(400, 400);
}
protected Control createContents(Composite parent) {
Composite composite = new Composite(parent, SWT.NONE);
composite.setLayout(new GridLayout(1, false));
Button preserveCase = new Button(composite, SWT.CHECK);
preserveCase.setText("&Preserve case");
final TreeViewer tv = new TreeViewer(composite);
tv.getTree().setLayoutData(new GridData(GridData.FILL_BOTH));
tv.setContentProvider(new FileTreeContentProvider());
tv.setLabelProvider(new FileTreeLabelProvider());
tv.setInput("root");
preserveCase.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent e) {
boolean preserve = ((Button) e.widget).getSelection();
FileTreeLabelProvider ftlp = (FileTreeLabelProvider) tv.getLabelProvider();
ftlp.setPreserveCase(preserve);
}
});
return composite;
}
public static void main(String[] args) {
new FileBrowserTreeViewer().run();
}
// 內部類 FileTreeContentProvider、FileTreeLabelProvider 同前...
}
執行效果:視窗左側顯示磁碟根目錄樹,右側核取方塊控制節點文字大小寫。注意:範例中 icons/file.gif 與 icons/directory.gif 需自行放置於專案根目錄下的 icons 資料夾。
TreeViewer 以 MVC 分離設計,將資料模型(內容提供器)與視覺表現(標籤提供器)解耦,支援複雜樹結構的高效渲染與動態更新。掌握 ITreeContentProvider 三大核心方法與 ILabelProvider 雙方法,即可構建從簡單目錄樹到複雜領域模型的各類樹形介面。