在SWT/JFace中,带复选框树最好使用ContainerCheckedTreeViewer(或者CheckedTreeViewer)来实现,今天遇到直接使用tree来实现的。
简单备记:
import java.awt.image.BufferedImage; import java.io.File; import javax.swing.Icon; import javax.swing.ImageIcon; import javax.swing.filechooser.FileSystemView; import javax.swing.plaf.IconUIResource; import org.eclipse.core.runtime.Platform; import org.eclipse.jface.dialogs.Dialog; import org.eclipse.jface.dialogs.IDialogConstants; import org.eclipse.swt.SWT; import org.eclipse.swt.events.SelectionAdapter; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.graphics.ImageData; import org.eclipse.swt.layout.FormAttachment; import org.eclipse.swt.layout.FormData; import org.eclipse.swt.layout.FormLayout; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Event; import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.Listener; import org.eclipse.swt.widgets.Shell; import org.eclipse.swt.widgets.Tree; import org.eclipse.swt.widgets.TreeItem; import org.eclipse.ui.internal.UIPlugin; /** * <p> * Title: MultiDirectoryDialog.java * </p> * <p> * Description: 文件选择框,支持多选 * </p> * */ public class MultiDirectoryDialog extends Dialog { // 菜单提示 private String message = ""; private Shell parent; // 列表树 private Tree tree; // 用来获取系统文件的相关信息 private FileSystemView fsv; // 用来存放选择的文件夹,用分号隔开 private StringBuilder resultFile = new StringBuilder(""); /** * 构造方法 * * @param parent * 父类 */ public MultiDirectoryDialog(Shell parent) { super(parent); this.parent = parent; } /* * (non-Javadoc) * * @see * org.eclipse.jface.dialogs.Dialog#createDialogArea(org.eclipse.swt.widgets * .Composite) */ protected Control createDialogArea(Composite parent) { parent.setDragDetect(false); Composite container = (Composite) super.createDialogArea(parent); container.setLayout(new FormLayout()); final Label showTipLabel = new Label(container, SWT.NONE | SWT.MULTI); showTipLabel.setText(message); final FormData fd_showTipLabel = new FormData(); fd_showTipLabel.top = new FormAttachment(0, 15); fd_showTipLabel.bottom = new FormAttachment(0, 32); fd_showTipLabel.right = new FormAttachment(0, 170); fd_showTipLabel.left = new FormAttachment(0, 30); showTipLabel.setLayoutData(fd_showTipLabel); final Composite treeComposite = new Composite(container, SWT.BORDER); treeComposite.setDragDetect(false); treeComposite.setLayout(new FormLayout()); // treeComposite.set // scrolledComposite.setAlwaysShowScrollBars(true); final FormData fd_scrolledComposite = new FormData(); fd_scrolledComposite.right = new FormAttachment(100, 0); fd_scrolledComposite.left = new FormAttachment(0, 0); fd_scrolledComposite.bottom = new FormAttachment(100, 0); fd_scrolledComposite.top = new FormAttachment(0, 50); treeComposite.setLayoutData(fd_scrolledComposite); // 新建树 tree = new Tree(treeComposite, SWT.DEFAULT); final FormData fd_tree = new FormData(); fd_tree.left = new FormAttachment(0, 5); fd_tree.bottom = new FormAttachment(0, 300); fd_tree.top = new FormAttachment(0, 0); fd_tree.right = new FormAttachment(0, 400); tree.setLayoutData(fd_tree); treeComposite.setData(tree); // 为树增加单击方法 tree.addListener(SWT.Expand, new Listener() { public void handleEvent(final Event event) { final TreeItem item = (TreeItem) event.item; TreeItem[] items = item.getItems(); for (int i = 0; i < items.length; i++) { if (items[i].getData() != null) return; items[i].dispose(); } // 初始化该文件下的节点 File file = (File) item.getData(); File[] childFile = file.listFiles(); for (File sfile : childFile) { if (sfile.isDirectory()) { initFile(item, sfile); } } } }); // 获取系统文件信息 fsv = FileSystemView.getFileSystemView(); File[] file = fsv.getRoots(); TreeItem item = new TreeItem(this.tree, SWT.NONE); String fileName = file[0].getName(); item.setText(fileName); item.setData(file[0]); Image img = getIcon(file[0]); if (img != null) item.setImage(img); // new TreeItem(item, 0); listFile(item, file[0], 1); return container; } /** * 本类用来初始化文件夹下的文件夹 * * @param treeitem * 父节点 * @param file * 要初始化的文件夹 * @param flag * 0:由外部调用,其它:递归调用 */ private void listFile(TreeItem treeitem, File file, int flag) { File[] childFile = file.listFiles(); if (flag == 0) {// 如果是外部调用,则再初始一级,以用来显示图标前的十一号。 for (File sfile : childFile) { if (sfile.isDirectory()) { // 初始化item的相关数据 TreeItem item = initFile(treeitem, sfile); // 初始化下一级item listFile(item, sfile, 1);// 只多这一行 } } } else {// 如果是自身调用,则说明已经为第二级文件夹,不需要再初始化下一级 for (File sfile : childFile) { if (sfile.isDirectory()) { initFile(treeitem, sfile); } } } } /** * 初始化item的相关数据 * * @param treeitem * 要初始化item的父item * @param file * 初始化item对应的file * @return 初始化后的item */ private TreeItem initFile(TreeItem treeitem, File file) { TreeItem item = new TreeItem(treeitem, SWT.NONE); item.setText(fsv.getSystemDisplayName(file)); item.setData(file); Image img = getIcon(file); if (img != null) item.setImage(img); // 如果还是文件夹,则加一个空节点,以使十号显示出来 if (file.isDirectory()) new TreeItem(item, 0); return item; } /** * 获取文件图标 * * @param file * 要获取图标的文件 * @return 图标 */ public Image getIcon(File file) { ImageData imageData = null; // 取得awt的icon对像并转化为swt的image对像 Icon icon = fsv.getSystemIcon(file); if (icon instanceof IconUIResource) { } else { // BufferedImage bi = ImageConvertor.getBufferedImage((ImageIcon) // icon); // imageData = ImageConvertor.getImageData(bi); // imageData = new Image(Display.getDefault(),50,50).getImageData(); } Image img = null; if (imageData != null) img = new Image(parent.getDisplay(), imageData); return img; } /** * Create contents of the button bar * * @param parent */ @Override protected void createButtonsForButtonBar(Composite parent) { createButton(parent, IDialogConstants.OK_ID, "确定", true); createButton(parent, IDialogConstants.CANCEL_ID, "取消", false); } /** SWT.MULTI创建出可以让用户作出多重选取的tree。SWT.CHECK样式的Tree会产生checkbox的Tree。如果使用了SWT.CHECK的样式,就需要判断哪些项目被选取了。通过调用TreeItem的getChecked()来判断某个项目是否被checked。下面的程序在循环中判断每个TreeItem的状态: TreeItem[] tia=t.getItems(); for(int i=0;i<tia.length;i++){ if(tia[i].getChecked()){ System.out.print("Checked"); } TreeItem []child=tia[i].getItems(); for(int n=0;n<child.length;n++) if(child[n].getChecked()) System.out.print("Checked"); } 以上的代码只能用在仅有一层子项目的tree上。多层的tree需要循环运算来处理。 SWT.CHECK样式的Tree对象在你需要让用户对Tree作出多重选取但又不想要SWT.MULTI模式的额外成本的时候是合适的(但若是要使用选取出的TreeItem来采取某些像是产生list内容这样的动作时则不适用) */ protected void buttonPressed(int buttonId) { if (buttonId == IDialogConstants.OK_ID) { TreeItem[] treeitem = tree.getItems(); for (int i = 0; i < treeitem.length; i++) { if (treeitem[i].getChecked()) { if (treeitem[i].getChecked()) { File file = (File) treeitem[i].getData(); resultFile.append(file.getPath()).append(";"); } } TreeItem[] child = treeitem[i].getItems(); for (int n = 0; n < child.length; n++) if (child[n].getChecked()) { File file = (File) child[n].getData(); resultFile.append(file.getPath()).append(";"); } } System.out.println(resultFile.toString()); } super.buttonPressed(buttonId); } /** * 设置 message * * @return */ public String getMessage() { return message; } /** * 获取message * * @param message */ public void setMessage(String message) { this.message = message; } /** * @return */ public StringBuilder getResultFile() { return resultFile; } /** * @param resultFile */ public void setResultFile(StringBuilder resultFile) { this.resultFile = resultFile; } public static void main(String[] args) { final Display display = Display.getDefault(); final Shell shell = new Shell(display, SWT.ON_TOP | SWT.CLOSE); shell.setSize(327, 253); Dialog dialog = new MultiDirectoryDialog(shell); if (dialog.open() == IDialogConstants.OK_ID) {// 是否单击“确定”按钮 System.out.println("helo"); } shell.open(); while (!shell.isDisposed()) { if (!display.readAndDispatch()) display.sleep(); } display.dispose(); } }