<html>
<head>
<meta http-equiv="Content-Language" content="zh-tw">
<meta name="GENERATOR" content="Microsoft FrontPage 5.0">
<meta name="ProgId" content="FrontPage.Editor.Document">
<meta http-equiv="Content-Type" content="text/html; charset=big5">
<title>Treeview menu test</title>
<style>
<!--
pre { border-style:dotted; border-width:1; color: #000000; font-family: Courier; padding-left: 4; background-color:
#FFFFFF; line-height:100%; padding-right:4; padding-top:1; padding-bottom:1; margin-top:0 }
-->
</style>
</head>
<body bgcolor="#F5F5F5" text="#000080" style="font-family: Arial; text-align:left; text-indent:0; " topmargin="10" leftmargin="10">
<p><b><font size="5" color="#000080">由資料庫讀入資料建立 Treeview 的速度測試</font></b></p>
<p><img border="0" src="samplescr.jpg" width="329" height="448"></p>
程式主要是透過不同的(讀取資料)方法去建立一個樹狀目錄,內建兩組資料(12 及 1,210 筆資料)及四種測試方法,當中可以測試速度上的差距。
<p style="margin-bottom: 0">方案一:<font color="#000000"><b>建立 query 去抓取子目錄</b></font></p>
<pre> <font color="#FF0000">///不斷的建立 query 去抓取下一層(子目錄)的程序 </font>
function QueryDetails(ParentMenuID : Integer ; TreeNode : TTreeNode) : Integer ;
var
qryMenu : TADOQuery;
MenuNode : TTreeNode;
aRecord : PMenuTreeItem ;
nCount, nAdded : Integer ;
begin
qryMenu := TADOQuery.Create(nil);
qryMenu.CursorLocation := clUseServer ;
qryMenu.Connection := connMenu ;
qryMenu.SQL.Add('SELECT * FROM menu_tree ' +
'WHERE parent_id = ' + IntToStr(ParentMenuID) + ' ' +
'ORDER BY menu_id') ;
qryMenu.Open ;
nCount := 0 ;
while not(qryMenu.Eof) do
begin
New(aRecord) ;
aRecord.ParentID := qryMenu.FieldByName('parent_id').AsInteger ;
aRecord.ItemID := qryMenu.FieldByName('menu_id').AsInteger ;
aRecord.Caption := qryMenu.FieldByName('menu_caption').AsString ;
MenuNode := TreeViewMenu.Items.AddChildObject(TreeNode,aRecord.Caption,aRecord);
Inc(nCount) ;
MenuNode.ImageIndex := 0;
MenuNode.SelectedIndex := 1;
MenuNode.StateIndex := -1;
nAdded := QueryDetails(aRecord.ItemID,MenuNode); <font color="#FF0000">//再抓取下一層(子目錄)</font>
Inc(nCount, nAdded) ;
qryMenu.Next;
end;
qryMenu.Close ;
qryMenu.Free ;
Result := nCount ;
end;
</pre>
<p style="margin-bottom: 0">方案二:<font color="#000000"><b>建立 TList 儲存第一層目錄以下的所有子目錄的資料,然後再一一放到 Treeview 內</b></font>
</p>
<pre>type
PQryMenuRec = ^TQryMenuRec ;
TQryMenuRec = Record
ItemID : Integer ;
ParentID : Integer ;
RecNo : Integer ; <font color="#FF0000">//儲存 query 的 record number,要再讀取資時先跳到該 record number</font>
Added : Boolean ;
end;
</pre>
<pre> while true do
begin
<font color="#FF0000">//為避免資料上的錯誤引至這個 while 成為 dead loop ,所以運行以下的 for .. loop 時,
// 每加入一筆資料到 Treeview ,nAdded 的值都會增加,當運行了一次 for .. loop 後,
// 而 nAdded 的值仍然停留在 0 值時,這個 while .. loop 亦可以停止再執行</font>
nAdded := 0 ;
ParentNode := nil ;
for i := 0 to (aMenuList.Count - 1) do
begin
<font color="#FF0000">//Added 表示已經放入 Treeview 的資料不再去處理</font>
if Not(PQryMenuRec(aMenuList.Items[i]).Added) then
begin
.
.
.
.
end;
end;
if nAdded = 0 then break ;
end;
</pre>
<p style="margin-bottom: 0">方案三及四:<b><font color="#000000">都是以方案二為基礎,而方案三只作出一點修改,加入一段程式碼,刪除一些已經加入到 Treeview 的資料,減少 for .... loop 運行的次數。</font></b>
</p>
<pre> if nAdded < aMenuList.Count then
begin
for i := (aMenuList.Count - 1) downto 0 do
begin
if PQryMenuRec(aMenuList.Items[i]).Added then
begin
Dispose(PQryMenuRec(aMenuList.Items[i])) ;
aMenuList.Delete(i);
end;
end;
end;
</pre>
<p style="margin-bottom: 0">方案四較特別之處是建立 query 時,使用倒序的方法: </p>
<pre> qryMenu.SQL.Add('SELECT * FROM menu_tree ' +
'WHERE parent_id > 0 ' +
'ORDER BY parent_id DESC, menu_id DESC') ;
</pre>
<p style="margin-bottom: 0">由 TList 內讀取資料放入 Treeview 時運行的 for .... loop 亦是逆行的,這是為了讓末段刪除那些已經加入到 Treeview 的資料:
</p>
<pre> for i := (aMenuList.Count - 1) downto 0 do
begin
.
.
.
.
Dispose(aMenuRec) ;
aMenuList.Delete(i);
end;
end;
</pre>
直接讀取所有資料儲存到 TList 內,免除以後再一次使用 query 。
<pre> while not(qryMenu.Eof) do
begin
New(aMenuRec) ;
aMenuRec.ParentID := qryMenu.FieldByName('parent_id').AsInteger ;
aMenuRec.ItemID := qryMenu.FieldByName('menu_id').AsInteger ;
aMenuRec.Caption := qryMenu.FieldByName('menu_caption').AsString ;
aMenuList.Add(aMenuRec) ;
qryMenu.Next;
end;
</pre>
<p style="margin-top: 0; margin-bottom: 0">尋找到 parent 時,同時間都抓取下一個子目錄,免除下一次再由頂層開始去尋找 parent
</p>
<pre>
if aMenuRec.ParentID = PMenuTreeItem(ParentNode.Data).ItemID then
begin
NextNode := ParentNode.GetNext ;
break ;
end;
ParentNode := ParentNode.GetNext ;
end;
end;
</pre>
就以上四個方案:
<table border="1" cellpadding="4" cellspacing="0" style="border-collapse: collapse" bordercolor="#C0C0C0" width="100%" id="AutoNumber1" bgcolor="#FFFFFF">
<tr>
<td align="center" width="200">方案</td>
<td align="center">用途</td>
</tr>
<tr>
<td align="center">(一)</td>
<td><font color="#000000"><b>parent → child 的配對</b></font></br>每建立一個子目錄,不論這個目錄內是否有子目錄(因為未能預先確定),都會建立一個 query 嘗試尋找它的子目錄</td>
</tr>
<tr>
<td align="center">(二)、(三)、(四)</td>
<td><font color="#000000"><b>child → parent 的配對</b></font></br>建立了第一層的目錄後,其餘的都放進一個 TList 內,運行 loop 去尋找 TList 內資料 的 parent</td>
</tr>
</table>
<ul style="margin-bottom: 10" >
<li >使用方案一所花的時間會最多,資料越多、樹狀結構越繁複,速度亦會再進一步減低。</li>
<li>如果資料不多(100 筆或以下的資料)的情況下,方案二、三、四的速度亦不相伯仲,但資料越多,方案四的速度就相對較二及三都要快。</li>
<li>個別情況下方案三要比方案二為慢。</li>
<li>走訪 query 的次數 (Query.First, Query.Next)、TreeView 的次數(TreeNode.GetNext)、looping 的次數及範圍都會影響到這個程式的速度,如果可以再進一步刪減這些動作,速度相對上亦可以再提昇。</li>
</ul>
其實這個示範程式是基於要一次過將全部資料都載到 Treeview 上,但很多情況下,程式設計員都會採用一種「打開時才載入 (load when expand)」的方法,這一個方法必定比以上四種方案都會快及更有效率。
<p> </p>
<p>作者:<a href="mailto:Stephen%20Au%20Yeung%3Csay@mac.com%3E">Stephen Au Yeung</a></p>
</body>
</html>
没有合适的资源?快使用搜索试试~ 我知道了~
资源推荐
资源详情
资源评论
















收起资源包目录














共 11 条
- 1
- 2
- 3
资源评论

chunyangsuhao
- 粉丝: 94
- 资源: 7438

上传资源 快速赚钱
我的内容管理 展开
我的资源 快来上传第一个资源
我的收益
登录查看自己的收益我的积分 登录查看自己的积分
我的C币 登录后查看C币余额
我的收藏
已下载
下载帮助

内容简介:Delphi读取数据库并建立Treeview树状视图目录..rar codefans.net codefans.net TreeviewMenuTest
相关资源
资源上传下载、课程学习等过程中有任何疑问或建议,欢迎提出宝贵意见哦~我们会及时处理!
点击此处反馈



安全验证
文档复制为VIP权益,开通VIP直接复制
