/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package cn.vearn.asynchtree;
import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import javax.swing.JCheckBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTree;
import javax.swing.SwingWorker;
import javax.swing.UIManager;
import javax.swing.event.TreeExpansionEvent;
import javax.swing.event.TreeExpansionListener;
import javax.swing.tree.DefaultTreeModel;
public class TestFrame extends JFrame {
private static final long serialVersionUID = 1L;
public TestFrame() {
super("asynch_load_tree");
JPanel northPanel = new JPanel();
final JCheckBox cb = new JCheckBox("点我看长时间阻塞EDT的后果");
northPanel.add(cb);
JPanel southPanel = new JPanel();
final JLabel label = new JLabel("异步加载树DEMO");
southPanel.add(label);
final DefaultTreeModel treeModel = initTreeModel();
final JTree tree = new JTree(treeModel); // JTree构造方法
tree.setShowsRootHandles(true); // 显示根结点左边的控制手柄
tree.collapseRow(0); // 初始时只显示根结点
// 注册TreeExpansionListener、监听结点展开事件
tree.addTreeExpansionListener(new TreeExpansionListener() {
@Override
public void treeExpanded(TreeExpansionEvent event) {
// 首先获取展开的结点
final MyTreeNode expandNode = (MyTreeNode) event.getPath().getLastPathComponent();
// 判断该节点是否已经被访问过
// 是——无需到数据库中读取、什么事也不做
// 否——开始异步加载
if (!expandNode.isVisited()) {
expandNode.setVisited(true); // 先改变visited字段的状态
tree.setEnabled(false); // 暂时禁用JTree
// 更新JLabel信息
label.setText("正在加载结点[" + expandNode.getNodeName() + "]...");
if (cb.isSelected()) {
long handleTime = asynchLoad(expandNode, treeModel);
treeModel.removeNodeFromParent(expandNode.getFirstLeaf()); // 加载完毕后要删除“载入中...”结点
tree.setEnabled(true); // 使JTree可用
label.setText("加载结点[" + expandNode.getNodeName() + "]完毕、耗时" + handleTime + "ms");
} else {
// 使用swingworker框架
new SwingWorker<Long, Void>() {
@Override
protected Long doInBackground() throws Exception {
return asynchLoad(expandNode, treeModel);
}
@Override
protected void done() {
treeModel.removeNodeFromParent(expandNode.getFirstLeaf());
treeModel.nodeStructureChanged(expandNode); // 通知视图结构改变
tree.setEnabled(true);
try {
// 获取doInBackground方法的返回值
label.setText("加载结点[" + expandNode.getNodeName() + "]完毕、耗时" + get() + "ms");
} catch (Exception ex) {
}
}
}.execute();
}
}
}
@Override
public void treeCollapsed(TreeExpansionEvent event) {
}
});
getContentPane().add(northPanel, BorderLayout.NORTH);
getContentPane().add(southPanel, BorderLayout.SOUTH);
getContentPane().add(new JScrollPane(tree), BorderLayout.CENTER);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(600, 450);
}
public static void main(String args[]) throws Exception {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); // 设定界面观感
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
new TestFrame().setVisible(true);
}
});
}
// 从数据库中读取根结点、并增加“载入中...”子结点
private DefaultTreeModel initTreeModel() {
DefaultTreeModel treeModel = null;
Connection conn = DBConn.getConn();
PreparedStatement ps = null;
ResultSet rs = null;
try {
ps = conn.prepareStatement("SELECT * FROM nodes WHERE parent_id=0");
rs = ps.executeQuery();
if (rs.next()) {
MyTreeNode root = new MyTreeNode(rs.getInt("node_id"), rs.getString("node_name"));
treeModel = new DefaultTreeModel(root);
if ("1".equals(rs.getString("is_leaf"))) {
addLoadingNode(treeModel, root);
}
}
} catch (Exception ex) {
} finally {
DBConn.closeAll(conn, ps, rs);
}
return treeModel;
}
// 增加“载入中...”子结点的方法
private void addLoadingNode(DefaultTreeModel treeModel, MyTreeNode parent) {
MyTreeNode loading = new MyTreeNode("载入中...");
treeModel.insertNodeInto(loading, parent, parent.getChildCount());
}
// 从数据表中读取expandNode的子结点.返回值为处理时长
private long asynchLoad(MyTreeNode expandNode, DefaultTreeModel treeModel) {
long handleTime = 0L; // 本次异步加载的处理时长
long start = System.currentTimeMillis(); // 开始处理的时刻
// 从数据库中读取父结点是expandNode的所有记录
Connection conn = DBConn.getConn();
PreparedStatement ps = null;
ResultSet rs = null;
try {
// Thread.sleep(3000); // sleep一段时间以便看清楚整个过程
ps = conn.prepareStatement("SELECT * FROM nodes WHERE parent_id=?");
ps.setInt(1, expandNode.getNodeId());
rs = ps.executeQuery();
while (rs.next()) {
MyTreeNode obj = new MyTreeNode(rs.getInt("node_id"), rs.getString("node_name"));
// 如果此结点不是叶子节点
// 给它加上一个“载入中...”的子结点
// 使这个结点左边绘制控制手柄.点击它(或者双击这个结点)可以触发TreeExpansionEvent
if ("1".equals(rs.getString("is_leaf"))) {
addLoadingNode(treeModel, obj);
}
// 把这个节点加入到expandNode中
treeModel.insertNodeInto(obj, expandNode, expandNode.getChildCount());
}
} catch (Exception ex) {
ex.printStackTrace();
} finally {
DBConn.closeAll(conn, ps, rs); // 关闭数据库连接
handleTime = System.currentTimeMillis() - start; // 计算出处理时长
}
return handleTime;
}
}
评论0