1. 程式人生 > >在Visual FoxPro中使用TreeView控制元件

在Visual FoxPro中使用TreeView控制元件

如果使用者在設計程式時,需要用一種樹形結構生動形象地顯示具有不同層次的資料,那麼TreeView控制元件將是最合適的選擇。TreeView控制元件可以將使用者選定的資料,也可以是從資料庫中檢索出來的資料,供使用者自由的選擇、展開或折迭收起。TreeView控制元件主要用以顯示層次資料之間的關係。TreeView控制元件的特點包括以下幾個方面:
1、將相互間有聯絡的資料用圖形與文字方式以樹形描繪,以樹形節點(Node物件)的形式展開或收起資料;
2、每一個節點可以用圖示和文字標籤來描述;
3、標籤可以設定為是否允許修改的屬性;
4、對層次深度和節點數目無限制,只受系統資源的限制。
另外,使用TreeView控制元件對管理資訊量很大的資料來說,是一個很好的方式,因為使用者能從中簡單快速的選擇到所需要的資料。Windows資源管理器就是TreeView控制元件、ImageList控制元件與ListView控制元件配合應用的一個例子。
TreeView控制元件是Microsoft Visual Studio 中的一個控制元件,它是Mscomctl.ocx檔案中的一組ActiveX控制元件的一部分。當安裝了Visual FoxPro或Visual Basic後就可以在Windows的System目錄中找到這個檔案。為了在釋出的應用程式中使用TreeView控制元件,必須將Mscomctl.ocx檔案與應用程式一起做成安裝盤釋出。這個控制元件在Visual FoxPro 5.0中的版本是5.0,但是該控制元件的5.0版本不支援6.0版本的一些屬性、方法和事件,所以要儘量使用6.0版本。如果沒有Visual FoxPro 6.0也可以,只要找到Mscomctl.ocx這個檔案並將其註冊,就可以在Visual FoxPro 5.0中使用該控制元件的6.0版本。
一個TreeView控制元件由若干Node物件組成,一個Node物件就是一個節點。一個TreeView控制元件只能有一個根節點(Root)。一個節點有若干子節點(Child),但必須有(除根節點以外)也只能有一個父節點(Parent)。建立TreeView控制元件之後,可以通過設定屬性與呼叫方法操作各Node物件,包括新增、刪除等。可以程式設計展開與折迭Node物件顯示或隱藏子節點。
在FoxPro主選單的“工具”選單的“選項”中“控制元件頁框”,將“ActiveX控制元件”的“Microsoft TreeView Control,Version 6.0”選定,然後單擊確定,即可將TreeView控制元件加入“表單控制元件工具欄”。單擊表單控制元件工具欄的檢視類按鈕,彈出一個選單,單擊其中的“ActiveX控制元件”,即可在“表單控制元件工具欄”看到TreeView控制元件。將ImageList控制元件加入“表單控制元件工具欄”的方法與TreeView控制元件的方法一樣。
TreeView的外觀只要看一下Windows資源管理器就很清楚了。要使用TreeView控制元件與其他普通控制元件一樣,TreeView控制元件也是由屬性、方法和事件控制的(以下假設表單加入的TreeView控制元件的Name屬性是Tree)。設計時在控制元件上單擊滑鼠右鍵會彈出一個快捷選單,單擊“TreeCtrl Properties”就會出現一個標題為“TreeCtrl屬性”的視窗,在這個視窗中可以設定控制元件的一些屬性。但這裡有一個“Bug”,如果在這裡設定與ImageList控制元件的關聯存不上盤,當時好象存上了,再次開啟還是老樣子。在後面Image屬性的介紹中再詳細說明任何解決這個問題。
一、Node物件的屬性
在控制元件上單擊右鍵,單擊彈出式選單的最後一項即可修改屬性。
1、Key(鍵值):一個節點的鍵值必須是唯一的字元型的值,控制元件用鍵值來區分節點,如果某兩個節點的鍵值相同將會出錯。鍵值可以由字母、下劃線、空格和數字等可列印字元組成,但不能是純數字的字串,否則會出錯。如用於顯示磁碟目錄,可以用路徑作為鍵值。ThisForm.Tree.SelectedItem.Key或ThisForm.Tree.Nodes.Item(Node.Index).Key返回控制元件當前選定的節點的鍵值。
2、Parent(父節點):一個節點只能有一個父節點,根節點沒有父節點。ThisForm.Tree.SelectedItem.Parent.Key返回控制元件當前選定的節點的父節點的鍵值。如果當前選定的節點沒有父節點,則這行程式碼就會出錯。可用ThisForm.Tree.SelectdeItem.Parent是否為空值(Isnull)或ThisForm.Tree.SelectedItem.Index是否等於1判斷該節點是否有父節點。
3、Child(子節點):ThisForm.Tree.SelectedItem.Child.Key返回TreeView控制元件中當前選定的節點的第一個子節點的鍵值,如果該節點無子節點,該行程式碼會出錯。可以使用下面這個屬性看一下它有沒有子節點。
4、Children(子節點數目):ThisForm.Tree.SelectedItem.Children返回TreeView控制元件中當前選定的節點的子節點的數目。
5、Text(節點標籤):該屬性返回使用者所看到的節點的標籤,不同節點的標籤允許相同,也可以是空字串。
6、LabelEdit:該屬性為0時雙擊標籤,即可編輯標籤。等於1時不可編輯。編輯標籤時會觸發AfterLabelEdit和BeforeLabelEdit事件。
7、Singlesel:該屬性為Ture時,被選定的節點如果有子節點將自動展開顯示子節點。
8、Sorted:當該屬性為Ture時,節點按字母順序排列。
9、Expanded:當該屬性為Ture時,表明該節點是展開的。
10、Next:返回TreeView控制元件中同為Node節點的父節點的子節點的下一個兄弟節點的物件。
11、Previous:返回TreeView控制元件中同為Node節點的父節點的子節點的前一個兄弟節點的物件。
12、Style:返回或設定圖形型別(圖示、文字、+/-號、直線)以及出現在TreeView控制元件中每一Node物件上的文字型別。
設定值 說明
0 僅為文字
1 圖示和文字
2 +/-和文字
3 +/-、圖示和文字
4 直線和文字
5 直線、圖示和文字
6 直線、+/-和文字
7 (預設)圖示、直線、+/-和文字

13、Count: Nodes集合中的節點總數。該屬性是Nodes集合的屬性。
14、Index:增加一個Node物件時就給其分配了索引值,儲存在該Node物件的Index屬性中。新成員的該屬性值也是Nodes集合的Count屬性值。
15、Image:對應節點的圖示鍵值。TreeView控制元件中的圖示是另外一個控制元件ImageList提供的,在這個控制元件中為每一個圖示指定一個唯一的鍵值,要改變節點的圖示只要改變這個屬性就可以了。在Visual FoxPro中TreeView控制元件有一個Bug,在設計時無法與ImageList相關聯(在VB中沒有此現象),這個問題可以解決,在表單的Init事件中加入下面三行就可以解決這個Bug(假定加入的ImageLiat控制元件Name屬性為Images)。
This.Tree.ImageList = This.Images
二、方法
1、Add:用於向TreeView控制元件加入節點
語法:Object.Add (Relative,Relationship, Key, Text, Image, Selectedimage)
①Object:物件名稱,本例為ThisForm.Tree;
②Relative:可選引數。已存在的Node物件的索引或鍵值。加入根節點時省略,加入子節點時是父節點的鍵值。
③Relationship:可選引數。指定Node物件的相對位置關係。
relationship值的設定如下:
常量 值 描述
TvwFirst 0 第一個。該Node節點放在relative命名的所有同級節點的前面
TvwLast 1 最後一個。該Node節點放在relative命名的所有同級節點的最後。後續增加的節點可以在該節點之後
TvwNext 2 (預設)下一個。該Node節點放置在relative命名的節點之後
TvwPrevious 3 前一個。該Node節點放置在relative命名的節點之前
TvwChild 4 子節點。該Node節點是relative命名節點的子節點

④Key:Node物件的鍵值。必須是字串。
⑤Text:Node物件的標籤。必須是字串。
⑥Image:可選引數。與ImageList控制元件關聯的影象索引或鍵值,也就是標籤前面的圖示。
⑦Selectedimage:可選引數。當Node物件選中時,所顯示的與ImageList控制元件關聯的影象索引或鍵值。比如:節點未選中時顯示關閉的資料夾圖示,選中時顯示開啟的資料夾圖示。
2、Remove:從Node集合(Nodes)中刪除一個節點。該節點的子節點將被一同刪除(如果有的話)。
語法:Object.Nodes.Remove(Key)
①Object:物件名稱,本例為ThisForm.Tree。
②Key:Node物件的鍵值。
3、Nodes( ):用Node物件的索引返回物件的引用。
語法:Object.Nodes(Index)
①Object:物件名稱,本例為ThisForm.Tree。
②Index:增加一個Node物件時給其分配的索引值。第一個加入的節點Index為1,第二個為2,依次類推。
4、Nodes( ):用Node物件的鍵值返回物件的引用。
語法:Object.Nodes(Key)
①Object:物件名稱,本例為ThisForm.Tree。
②Key: Node物件的鍵值。
三、事件
1、BeforeLabelEdit:在試圖編輯當前選中的Node物件標籤時該事件發生。在LabelEdit=1時該事件失效。
2、AfterLabelEdit:在編輯當前選中的Node物件標籤後事件發生。在LabelEdit=1時該事件失效。
3、Collapse:將已展開的節點摺疊時事件發生。該事件發生在標準的Click事件之前。該事件返回被摺疊的Node物件的引用。觸發Collapse事件有三種方法:
①設定Node物件的Expanded屬性為False.;
②雙擊展開的Node物件;
③TreeView控制元件的Style屬性為2、3、6或7時,單擊“-”圖象。
4、Expand:在控制元件有子節點的Node物件擴充套件開時事件發生。該事件發生在標準的Click事件之前。該事件返回被展開的Node物件的引用。觸發Expanded事件有三種方法:
①設定Node物件的Expanded屬性為True.;
②雙擊帶有子節點的Node物件;
③TreeView控制元件的Style屬性為2、3、6或7時,單擊“+”圖象。
5、NodeClick:單擊Node物件時該事件發生。該事件發生在標準的Click事件之前。在單擊節點物件之外的控制元件任何部位,標準的Click事件發生。
四、舉例
1、用表中資料增加節點。該表有_Parent(父節點鍵值),_Key(本節點鍵值),Text(節點文字),3個欄位。
select LS
SCAN
IF ALLTRIM(parent) = "0"
Node = this.nodes.add(,1,ALLTRIM(LS.key),ALLTRIM(LS.Text),,)
*加入根節點
ELSE
Node =this.nodes.add(ALLTRIM(LS.parent),4,ALLTRIM(LS.key),ALLTRIM(LS.Text),,)
ENDIF
ENDSCAN
2、將所有節點資訊存入一個臨時表。該例將控制元件每一個節點的鍵值(_key)、標籤(T_text)和父節點鍵值(_parent)存入臨時表:LS。
O=ThisForm.Tree  
*為了減少程式碼數量,建立一個物件變數來代替很長的物件名稱。
Create Cursor LS (_key c(10),T_text n(40),_parent c(10)) *建立臨時表LS
For I=1 to O.Nodes.count()
Insert Into LS Value(O.Nodes(I).Key,O.Nodes(I).Text,O.Nodes(I)._parent.Key)
Endfor
3、獲取一個節點的所有父節點與子節點,並將其存入一個臨時表LS1。臨時表LS1存入所有節點的父節點鍵值(_parent)、本節點鍵值(_key)和本節點標籤(T_text)。LS2用來模擬堆疊。
O=ThisForm.Tree1 *建立物件變數既可以減少程式碼輸入又可增加可讀性只是速度稍慢
Create Cursor LS1 (_parent c(10),_key c(10),T_text c(60))
Create Cursor LS2 (_index n(10))
Select LS2
node_index=o.SelectedItem.Index *Tree1當前選定的節點索引值
*下面程式碼獲取該節點的父節點
Do while .t.
Insert Into Ls2 Value(o.Nodes(node_index).Index)  
If o.Nodes(node_index).Parent.Index=1
Exit
Endif
node_index=o.Nodes(node_index).Parent.Index
Enddo
*由於上面程式碼獲取的父節點排在子節點的後面,下面這個迴圈把順序倒過來,使輩分高的節點排在前面。
Do while .t.
Go Bottom
node_index=LS2._index
If node_index=0
Exit
Endif
Insert Into LS1 Value(o.Nodes(node_index).Parent.Key,;
o.Nodes(node_index).Key,;
o.Nodes(node_index).Text)
Delete
Enddo

Select LS2
child_number=o.SelectedItem.Children
If Child_number>0
node_index=o.SelectedItem.Index
Do while node_index#0
Insert Into LS2 Value(o.Nodes(node_index).Child.Index)
Insert Into Ls1 Value(o.Nodes(node_index).Key,;
o.Nodes(node_index).Child.Key,;
o.Nodes(node_index).Child.Text)
For i=2 to child_number
node_index=LS2._index
Insert Into LS2 Value(o.Nodes(node_index).Next.Index)
Insert Into LS1 Value(o.Nodes(node_index).Next.Parent.Key,;
o.Nodes(node_index).Next.Key,;
o.Nodes(node_index).Next.Text)
Endfor
Select LS2
Go Bottom
Do while .t.
node_index=LS2._index
If node_index=0
Exit
Endif
child_number=o.Nodes(node_index).Children
If child_number=0
Delete
Go Bottom
Loop
Else
Delete
Exit
Endif
Enddo
Go Bottom
Enddo
Endif
Select Ls2
Use
五、其它:
1、TreeView控制元件缺少一個檢測節點是否存在的函式(不知道是不是我沒有發現),當向一個控制元件加入一個節點時,如果鍵值重複就會出錯。有一個辦法“解決”問題,我暫且稱之為“賴皮”演算法,就是用On Error Lerror=.T.忽略所有錯誤,之後再用On Error 解除就會相安無事。見下例。如果沒有第一行,當檢測的節點不存在時,就會有錯誤視窗彈出。
On Error Lerror=.T.
If Isnull(Thisform.Tree.Nodes(Key))
On Error
Return(.f.)
Else
On Error
Return(.T.)
Endif
2、最後簡要介紹ImagesList控制元件的使用方法。
ImageList控制元件與TreeView控制元件都在檔案Mscomctl.ocx中。在表單執行時該控制元件不可見,它的任務就是向其他控制元件提供圖示。設計時在控制元件上單擊滑鼠右鍵,會彈出一個快捷選單,單擊“ImageListCtrl Properties”就會出現一個標題為“ImageListCtrl 屬性”的視窗,在這個視窗中可以設定控制元件的屬性。在這裡先設定圖示的大小,加入圖示後大小就無法改變了。加入圖示並指定圖示的索引或鍵值後,就可以由其他控制元件隨意呼叫圖示了。5.0版的ImageList控制元件只能加入圖示,6.0版的可以加入圖片(當然不能太大),所以儘可能使用高版本。