在用SWT进行桌面开发的过程中需要经常使用到Tree组件,往往数据量大的时候创建Tree非常耗时间,直接导致界面假死,这时候虚拟树就起到关键作用了。
以下是一个解析JAR文件构建Tree的例子:
测试使用的是jdk下的tool.jar文件,该文件比较大,内部包含文件也比较多,用普通的Tree构建肯定是死慢的。
package test;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.FileDialog;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Tree;
import org.eclipse.swt.widgets.TreeItem;
/**
* 测试虚拟树
* @author xoHome
*/
public class LoadJarTest {
public static void main(String[] args) {
try {
//new LoadJarTest().test();
new LoadJarTest().test2();
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 树目录结构
*/
class Entry {
List<String> file = new ArrayList<String>();
Map<String, Entry> dire = new LinkedHashMap<String, Entry>();
void put(String url, boolean isDir) {
String[] us = url.split("/");
// 找出最根目录
int s = 0, e = isDir ? us.length : us.length - 1;
Entry entry = this;
for (; s < e; s++) {
Entry ey = entry.dire.get(us[s]);
if (ey == null) {
ey = new Entry();
entry.dire.put(us[s], ey);
}
entry = ey;
}
if (!isDir) {
entry.file.add(us[us.length - 1]);
}
}
Map.Entry<String, Entry> getDirEntry(int index) {
return (Map.Entry<String, Entry>) dire.entrySet().toArray()[index];
}
}
public Entry createTree(String url) throws IOException {
JarFile jar = new JarFile(new File(url));
Enumeration<JarEntry> enumeration = jar.entries();
Entry entry = new Entry();
for (JarEntry jentry; enumeration.hasMoreElements();) {
jentry = enumeration.nextElement();
entry.put(jentry.getName(), jentry.isDirectory());
}
// 打印测试
//print(entry, 0);
return entry;
}
public void test2() {
final Display display = Display.getDefault();
final Shell shell = new Shell(display);
shell.setBounds(500, 150, 450, 500);
final Tree tree = new Tree(shell, SWT.VIRTUAL | SWT.BORDER | SWT.SCROLL_LINE);
tree.setBounds(0, 0, 350, 500);
tree.addListener(SWT.SetData, new Listener() {
@Override
public void handleEvent(Event event) {
TreeItem item = (TreeItem) event.item;
TreeItem parentItem = item.getParentItem();
int index = event.index;
Entry entry = (Entry) (parentItem == null ? tree.getData() : parentItem.getData());
boolean isDir = entry.dire.size() > index;
if (isDir) {
Map.Entry<String, Entry> dirEntry = entry.getDirEntry(index);
StringBuilder pack = new StringBuilder(dirEntry.getKey());
Entry next = dirEntry.getValue();
while (true) {
if(next.dire.size() == 1 && next.file.size() == 0){
dirEntry = next.getDirEntry(0);
pack.append(".").append(dirEntry.getKey());
next = dirEntry.getValue();
continue;
}
break;
}
item.setText(pack.toString());
item.setData(next);
item.setItemCount(next.dire.size() + next.file.size());
} else {
item.setText(entry.file.get(index - entry.dire.size()));
}
}
});
Button btn = new Button(shell, SWT.NONE);
btn.setBounds(355, 10, 70, 25);
btn.setText("选择JAR");
btn.addListener(SWT.Selection, new Listener() {
@Override
public void handleEvent(Event arg0) {
FileDialog dialog = new FileDialog(shell);
dialog.setText("选择Jar文件");
dialog.setFilterExtensions(new String[] { "*.jar" });
String path = dialog.open();
if (path == null) {
return;
}
Entry entry = null;
try {
entry = createTree(path);
} catch (IOException e) {
e.printStackTrace();
return;
}
tree.clearAll(true);
tree.setData(entry);
tree.setItemCount(entry.dire.size() + entry.file.size());
}
});
shell.open();
while (!shell.isDisposed()) {
if(!display.readAndDispatch()){
display.sleep();
}
}
display.dispose();
}
/**
* 打印测试
* @param entry
* @param margin
*/
public void print(Entry entry, int margin) {
StringBuffer space = new StringBuffer();
for (int i = 0; i < margin; i++) {
space.append("\t");
}
if (entry.dire.size() > 0) {
Set<Map.Entry<String, Entry>> sets = entry.dire.entrySet();
for (Map.Entry<String, Entry> es : sets) {
System.out.println(space.toString() + es.getKey());
Entry next = es.getValue();
if (next != null) {
print(next, margin + 1);
}
}
}
if (entry.file.size() > 0) {
for (String f : entry.file) {
System.out.println(space.toString() + f);
}
}
}
}
附一个预览截图: