Giới thiệu.
Tôi hy vọng bạn tìm thấy hướng dẫn tuần trước về ImageCombo Control hữu ích cho các Dự án Microsoft Access của bạn. Với Điều khiển TreeView ImageCombo, chúng tôi có thể tạo một Menu thả xuống đẹp mắt, với một số tùy chọn và chứa nó trong một không gian nhỏ trên biểu mẫu.
Tương tự như vậy, trong một phiên trước đó, chúng ta đã học cách Thêm nút mới ở một vị trí cụ thể trên hệ thống phân cấp nút hoặc Xóa một nút và thêm một nút mới để định vị lại một nút trên Điều khiển chế độ xem dạng cây.
Phương thức này yêu cầu tạo một bản ghi mới trong bảng nguồn cho nút mới. Hoặc xóa một bản ghi hiện có và tạo một bản ghi mới để di chuyển một nút hiện có nhằm biến chúng thành vĩnh viễn. Theo một cách nào đó, với việc sử dụng Chức năng Thêm / Xóa, chúng ta có thể thêm các Nút mới hoặc sắp xếp lại các Nút hiện có trên Điều khiển TreeView. Liên quan đến việc sắp xếp lại các Nút, chúng tôi có một cách tốt hơn để làm điều đó, thay vì xóa các Nút và tạo lại chúng. Kéo Node từ vị trí hiện tại của nó và thả nó vào nơi chúng ta muốn trên TreeView Control. Đây là những gì chúng ta sẽ tìm hiểu trong tập này
Cách tiếp cận đơn giản này chỉ cần cập nhật sự thay đổi của giá trị trường ParentID của các bản ghi liên quan để thay đổi vĩnh viễn.
Các chủ đề được đề cập cho đến nay trong các Phiên trước đó.
- Hướng dẫn Điều khiển Microsoft TreeView
- Tạo Menu Truy cập với Điều khiển TreeView
- Gán hình ảnh cho điều khiển TreeView
- Gán hình ảnh cho TreeView Control-2
- Kiểm soát TreeView Kiểm tra-Đánh dấu Thêm nút Xóa
- Trình đơn truy cập thả xuống TreeView ImageCombo
Tuy nhiên, chúng tôi có thể gặp một số thách thức khi sử dụng phương pháp này và chúng tôi sẽ đến với vấn đề đó sau trong Phiên này.
Bảng và Biểu mẫu Dữ liệu Demo.
Chúng ta cần một Bảng và một Biểu mẫu. Chúng tôi đã có một bảng phù hợp với tên Mẫu được tạo trong một Phiên hướng dẫn trước đó. Nếu bạn đã tải xuống Cơ sở dữ liệu Demo, từ trang liên kết thứ hai được cung cấp ở trên trước đó, thì bạn cũng có thể sử dụng Cơ sở dữ liệu đó cho Phiên này. Chúng tôi sẽ sử dụng các đối tượng sau từ Cơ sở dữ liệu đó cho các thử nghiệm Kéo-Thả của chúng tôi:
- Bảng: Mẫu
- Biểu mẫu: frmSample
Hình ảnh điều khiển TreeView trên frmSample với dữ liệu demo được cung cấp bên dưới để tham khảo:
Bạn có thể tải xuống Cơ sở dữ liệu demo ( ProjectMenu.zip ) từ Trang liên kết thứ hai được cung cấp ở trên và trích xuất ProjectMenu.accdb cơ sở dữ liệu.
Biểu mẫu mới để chạy thử kéo thả.
-
Mở cơ sở dữ liệu ProjectMenu.accdb.
-
Tạo một bản sao của bảng Mẫu và đặt tên là Sample_bk, giữ nó an toàn, chúng tôi sẽ cần dữ liệu ban đầu của nó mà không cần thay đổi sau này. Khi chúng tôi thử nghiệm với phương pháp kéo-thả, cần phải cập nhật giá trị trường ParentId trên Bảng demo mẫu. Tuy nhiên, chúng tôi cần dữ liệu gốc sau này, nếu không có những thay đổi này.
-
Tạo Biểu mẫu mới với tên frmDragDrop .
-
Thiết kế biểu mẫu frmDragDrop sẽ giống như hình dưới đây khi bạn hoàn thành.
-
Chèn Điều khiển TreeView từ Danh sách điều khiển ActiveX và đặt nó trên biểu mẫu, để lại đủ không gian phía trên điều khiển, để chúng ta có thể tạo hai Nút lệnh và Nhãn tiêu đề phía trên nó. Kéo chốt định cỡ ở góc dưới cùng bên phải để làm cho nó đủ lớn để hiển thị tất cả các Nút mà không cần cuộn.
-
Thay đổi Tên Giá trị thuộc tính của Điều khiển TreeView thành TreeView0 .
-
Chèn một nút lệnh ở trên và cạnh trái của Điều khiển TreeView. Thay đổi Tên Giá trị thuộc tính thành cmdExpand và Chú thích giá trị thành Mở rộng tất cả .
- Chèn Nút lệnh thứ hai ở trên và vào cạnh bên phải của Điều khiển TreeView. Thay đổi Tên Giá trị thuộc tính thành cmdCollapse và Chú thích Giá trị thuộc tính để Thu gọn tất cả.
-
Chèn một Điều khiển Nhãn phía trên các Nút Lệnh, đủ rộng để viết Tiêu đề như được hiển thị ở trên và thay đổi Kích thước Phông chữ 14.
-
Bỏ qua Điều khiển ImageList, hiện tại, tôi đã nhận xét về các Dòng mã sửa đổi số chỉ mục Node ImageList. Sau đó, bạn có thể Nhập Điều khiển Danh sách Hình ảnh với Hình ảnh được tải lên theo cách thủ công, từ Cơ sở dữ liệu Demo Hướng dẫn trước đó của chúng tôi (từ Trang liên kết thứ 4 được đưa ra ở trên) và sử dụng nó để hiển thị Node-Hình ảnh trên Nodes. Khi các vị trí của Nút được thay đổi trong các hành động Kéo thả, chúng ta cần thay đổi Hình ảnh của Nút cũng tùy thuộc vào vị trí của Nút (Nút cấp gốc hoặc Nút con) trên Điều khiển TreeView.
Mã Mô-đun Biểu mẫu Kéo-Thả.
-
Hiển thị Mô-đun mã VBA của Biểu mẫu frmDragDrop, Sao chép và Dán Mã VBA sau (đây chỉ là nửa đầu của Mã mô-đun biểu mẫu) vào Mô-đun lớp của Biểu mẫu frmDragDrop và Lưu Biểu mẫu:
Option Compare Database Option Explicit Dim tv As MSComctlLib.TreeView Dim db As DAO.Database Dim rst As DAO.Recordset Dim imgListObj As MSComctlLib.ImageList Const KeyPrfx As String = "X" Private Sub Form_Open(Cancel As Integer) Set tv = Me.TreeView0.Object 'Set imgListObj = Me.ImageList1.Object 'tv.ImageList = imgListObj LoadTreeView End Sub Sub LoadTreeView() Dim strKey As String Dim strPKey As String Dim strText As String Dim strsQL As String strsQL = "SELECT * FROM Sample ORDER BY ID" Set db = CurrentDb Set rst = db.OpenRecordset(strsQL, dbOpenDynaset) tv.Nodes.Clear 'Add all Items are added as Root Nodes Do While Not rst.BOF And Not rst.EOF strKey = KeyPrfx & CStr(rst!ID) strText = rst!desc tv.Nodes.Add , , strKey, strText 'With tv.Nodes.Item(strKey) ' .Image = 1 ' .SelectedImage = 4 'End With rst.MoveNext Loop 'Prepare to update the Parent-Key of Nodes 'wherever applicable to move and position the Child Nodes strPKey = "" rst.MoveFirst Do While Not rst.EOF strPKey = Nz(rst!parentid, "") If Len(strPKey) > 0 Then strPKey = KeyPrfx & strPKey strKey = KeyPrfx & CStr(rst!ID) strText = rst!desc 'Move the Child Node under it's Parent-Node Set tv.Nodes.Item(strKey).Parent = tv.Nodes.Item(strPKey) 'Update Image and SelectedImage Properties 'with ImageList Index numbers 'With tv.Nodes.Item(strKey) ' .Image = 2 ' .SelectedImage = 3 'End With End If rst.MoveNext Loop rst.Close Set rst = Nothing Set db = Nothing End Sub Private Sub TreeView0_NodeClick(ByVal Node As Object) Dim SelectionNode As MSComctlLib.Node 'Ensure that the clicked node equals the selected node in the tree If Not Node Is Nothing Then Set SelectionNode = Node If SelectionNode.Expanded = True Then SelectionNode.Expanded = False Else SelectionNode.Expanded = True End If End If End Sub Private Sub cmdCollapse_Click() Dim tmpnod As MSComctlLib.Node For Each tmpnod In tv.Nodes If tmpnod.Expanded = True Then tmpnod.Expanded = False End If Next End Sub Private Sub cmdExpand_Click() Dim tmpnod As MSComctlLib.Node For Each tmpnod In tv.Nodes If tmpnod.Expanded = False Then tmpnod.Expanded = True End If Next End Sub
Tôi biết bạn đã quen thuộc với Mã trên, nếu bạn đã xem qua các Tập trước đó, ngoại trừ LoadTreeView () chương trình con với một số thay đổi. Ở đây, việc điền các Nút TreeView đã được chia thành một quy trình gồm hai bước.
Tóm lại, đây là những gì sẽ xảy ra trong Chương trình con này.
-
Tất cả các bản ghi trên Mẫu Bảng đã được tải dưới dạng Nút cấp gốc của Điều khiển TreeView, với giá trị trường ID là Khóa, trong bước đầu tiên.
-
Một lần nữa, những bản ghi này đã được đọc lần thứ hai và kiểm tra giá trị trong ParentId , nếu trống thì Nút sẽ được giữ lại làm Nút cấp gốc.
-
Nếu trường ParentID có Giá trị thì xác định Node với giá trị ParentID là Node-Key và di chuyển Nút hiện tại làm Nút con của nó hoặc [ Relative] Tham số (trong số Thêm () Phương pháp ) giá trị được cập nhật.
-
Mặc dù có vẻ như quy trình điền Node hai bước là một bài tập không cần thiết, nhưng có một lý do chính đáng tại sao chúng ta phải làm theo phương pháp này. Chúng tôi sẽ quay lại vấn đề này sau một chút và bạn sẽ biết nó mà không cần giải thích nhiều.
-
Trên Thiết kế của Biểu mẫu, tôi đã đưa ra Điều khiển Danh sách Hình ảnh. Bạn có thể chèn Điều khiển ActiveX của ImageList và tải lên một số hình ảnh trong đó theo cách thủ công từ đĩa hoặc sao chép và dán điều khiển này với các hình ảnh từ Tải xuống Cơ sở dữ liệu Demo trước đó. Trong cả hai trường hợp, hãy đảm bảo rằng tên của điều khiển ImageList là ImageList1 . Nếu không, bạn cần thay đổi tên trong Mã.
-
Sau đó, kích hoạt các dòng được chú thích trong Thủ tục sự kiện Form_Open (). Bật các dòng sau bằng cách xóa biểu tượng chú thích khỏi đầu dòng:
'Set imgListObj = Me.ImageList1.Object 'tv.ImageList = imgListObj
-
Trong TreeView0_ OLEDragDrop () Chương trình con (trong phần thứ 2 của Mã VBA) bật Tham số chỉ mục hình ảnh của các nút, bằng cách loại bỏ các ký hiệu Chú thích khỏi các dòng đó. Với những thay đổi này, Hình ảnh nút sẽ xuất hiện trên Điều khiển TreeView. Nếu bạn có Kiểm soát danh sách hình ảnh của riêng mình với Hình ảnh đã tải lên thì hãy thay đổi Số chỉ mục dựa trên Hình ảnh bạn muốn chèn vào các nút.
TreeView0_NodeClick () Quy trình sự kiện Mở rộng nút hiện tại, nếu các Nút con ở trạng thái thu gọn, nếu không, các Nút con sẽ được Thu gọn. Thông thường, hành động này được kiểm soát (không có Mã) bằng cách nhấp vào +/- Biểu tượng trên dòng cây của nút có nút con.
Các chương trình con cmdExpand_Click () và cmdCollapse_Click () Sự kiện Mở rộng tất cả các Nút và thu gọn tất cả các Nút tương ứng.
Khi đoạn mã trên chạy, màn hình sẽ giống như Hình ảnh Dạng xem Biểu mẫu được cung cấp bên dưới:
-
Bạn có thể lưu frmDragDrop Tạo và mở nó ở Dạng xem Thường. Nếu mọi thứ diễn ra tốt đẹp thì bạn sẽ thấy màn hình trên. Hãy thử Mở rộng tất cả và Thu gọn tất cả Các nút lệnh và kiểm tra xem chúng có đang hoạt động hay không. Nếu không, hãy kiểm tra lại các cài đặt sau đã chính xác hay chưa:
-
i) Tên của Điều khiển TreeView là: TreeView0
-
ii) Hiển thị Trang thuộc tính của Exampand All Nút lệnh và chọn [Thủ tục sự kiện] trong Khi nhấp Thuộc tính sự kiện.
-
iii) Đảm bảo rằng cài đặt tương tự vẫn nguyên vẹn cho Thu gọn tất cả Nút lệnh cũng có.
-
iv) Nhấp vào một nút, có các nút con, để xem liệu chúng thu gọn hay mở rộng khi nhấp chuột lặp lại.
-
v) Nếu ImageList Control được đặt trên Biểu mẫu thì tên của nó phải là ImageList1 .
Hãy để chúng tôi tiếp tục với phần thứ hai của Mã VBA triển khai Sự kiện kéo-thả.
Nửa thứ hai của mã VBA.
-
-
Sao chép Phần thứ hai sau của Mã VBA, trên Mô-đun biểu mẫu frmDragDrop, thực hiện hành động Kéo-Thả và Dán nó bên dưới Mã hiện có:
Private Sub TreeView0_OLEStartDrag(Data As Object, AllowedEffects As Long) Set Me.TreeView0.SelectedItem = Nothing End Sub Private Sub TreeView0_OLEDragOver(Data As Object, _ Effect As Long, _ Button As Integer, _ Shift As Integer, _ x As Single, _ y As Single, _ State As Integer) Dim SelectedNode As MSComctlLib.Node Dim nodOver As MSComctlLib.Node If tv.SelectedItem Is Nothing Then 'Select a node if one is not selected Set SelectedNode = tv.HitTest(x, y) If Not SelectedNode Is Nothing Then SelectedNode.Selected = True End If Else If tv.HitTest(x, y) Is Nothing Then 'do nothing Else 'Highlight the node the mouse is over Set nodOver = tv.HitTest(x, y) Set tv.DropHighlight = nodOver End If End If End Sub Private Sub TreeView0_OLEDragDrop(Data As Object, _ Effect As Long, _ Button As Integer, _ Shift As Integer, _ x As Single, _ y As Single) Dim sourceNode As MSComctlLib.Node Dim SourceParentNode As MSComctlLib.Node Dim targetNode As MSComctlLib.Node Dim tmpRootNode As MSComctlLib.Node Dim strtmpNodKey As String Dim ChildNode As MSComctlLib.Node Dim strSPKey As String Dim strTargetKey As String Dim strsQL As String Dim intKey As Integer Dim intPKey As Integer On Error Resume Next Select Case Screen.ActiveControl.Name Case TreeView0.Name Set sourceNode = tv.SelectedItem End Select 'Get Source Parent Node & Target Node Reference Set SourceParentNode = sourceNode.Parent Set targetNode = tv.HitTest(x, y) 'If any errors then exit If Err <> 0 Then MsgBox Err & " : " & Err.Description, vbInformation + vbCritical, "OLEDragDrop()" Err.Clear Exit Sub Else On Error GoTo 0 End If 'Get/define Source parent Node Key to compare it with Target Node Key If SourceParentNode Is Nothing Then strSPKey = "Empty" Else strSPKey = SourceParentNode.Key End If 'Check the Target Node/Location and define the Key Select Case True Case targetNode Is Nothing strTargetKey = "Empty" Case targetNode.Key = "" strTargetKey = "Empty" Set targetNode = Nothing Case Else strTargetKey = targetNode.Key End Select 'Make sure the Target Node is not the source Node's own parent If strTargetKey = strSPKey Then Exit Sub 'Track User's Node move action, check for error. On Error Resume Next If targetNode Is Nothing Then 'If target Node is Nothing (the Node dropped in the empty area), 'then the Node must be moved to the Root-level 'save the original sourceNode.Key strtmpNodKey = sourceNode.Key 'Modify the source Node Key, with addition of some text, say 'Empty', like 'X5Empty' 'So that a temporary Node can be created with the original source Node key. 'Note: Two Nodes with the same Key cannot remain in memory at the same time. 'The Source Node with key 'X5Empty' deleted later, 'temporary Node takes it's droped location. sourceNode.Key = sourceNode.Key & strTargetKey 'Create the temporary Root Node, with original sourceNode Key Set tmpRootNode = tv.Nodes.Add(, , strtmpNodKey, sourceNode.Text) 'define the Root Node image indexes 'With tmpRootNode ' .Image = 1 ' .SelectedImage = 4 'End With 'Move all child Nodes from SourceNode,if any, 'as tmpRootNode's Children Do Until sourceNode.Children = 0 Set sourceNode.Child.Parent = tmpRootNode 'modify Node image indexes 'With sourceNode ' .Image = 2 ' .SelectedImage = 3 'End With Loop 'Delete the Source Node with modified Key from TreeView tv.Nodes.Remove sourceNode.Index 'Move the tmpRootNode with original Key 'to the dropped location on TreeView Set sourceNode = tmpRootNode Else 'Move the sourceNode under targetNode as child Set sourceNode.Parent = targetNode 'modify Node image indexes 'With sourceNode ' .Image = 2 ' .SelectedImage = 3 'End With End If 'Notify, if there was an Error then Exit, else Update PrentID of related Record. If Err <> 0 Then MsgBox Err & " : " & "Unable to move:" & vbCrLf & Err.Description, vbInformation + vbCritical, "DragDrop2()" Exit Sub Else 'Build and execute the SQL statement to update the record If targetNode Is Nothing Then intKey = Val(Mid(sourceNode.Key, 2)) strsQL = "UPDATE Sample SET ParentID = Null" & _ " WHERE ID = " & intKey Else intKey = Val(Mid(sourceNode.Key, 2)) intPKey = Val(Mid(targetNode.Key, 2)) strsQL = "UPDATE sample SET ParentID = " & intPKey & _ " WHERE ID = " & intKey End If 'Modify the table records CurrentDb.Execute strsQL, dbFailOnError 'If an error raised then refresh TreeView and exit If Err <> 0 Then MsgBox Err & " : " & Err.Description LoadTreeView 'Refresh/display TreeView without changes Else 'Sort Nodes If sourceNode.Parent Is Nothing Then sourceNode.Root.Sorted = True Else sourceNode.Parent.Sorted = True End If tv.Nodes(sourceNode.Key).Selected = True End If End If On Error GoTo 0 End Sub Private Sub TreeView0_OLECompleteDrag(Effect As Long) 'Turn off the drophighlight Set tv.DropHighlight = Nothing End Sub Private Sub Form_Close() Set tv = Nothing End Sub
Đối với hành động Kéo-Thả, có bốn chương trình con, chúng sẽ tự động thực thi khi bạn Kéo (các) Nút, đánh dấu Nút khi được di chuyển qua các Nút khác và cuối cùng thả nó trên một Nút khác hoặc trên vùng trống cấp Gốc .
Các chương trình con chính của Quy tắc.
- TreeView0_OLEStartDrag () - Khởi tạo mục đã chọn và đặt Nút thành Không có gì
- TreeView0_OLEDragOver () - Hoạt động giống như Sự kiện di chuyển chuột, làm nổi bật Nút, khi kéo một Nút phía trên nó, trên đường đến Nút mục tiêu.
- TreeView0_OLEDragDrop () - Thực hiện kiểm tra và điều khiển, định vị (các) Nút ở Vị trí bị thả và cập nhật bản ghi trên Bảng cơ sở.
- TreeView0_OLECompleteDrag () - Thuộc tính DropHighlight được đặt thành Không có gì.
Chúng tôi có thể thực hiện các hoạt động Kéo và Thả với TreeView0_OLEDragDrop () Chương trình con một mình. Trong trường hợp đó, sẽ không có bất kỳ Nút nào được tô sáng, khi Nút nguồn di chuyển qua các Nút khác, từ vị trí này sang vị trí khác, ngoại trừ việc Con trỏ chuột chuyển sang kéo mũi tên thứ hai phía sau nó, như trong hình ảnh mẫu bên dưới :
Vì vậy, chúng ta sẽ chú ý đến chương trình con này và kiểm tra Code chi tiết ngay từ đầu. Ở phần đầu của chương trình con, chúng ta đã khai báo các nút và biến chuỗi cần thiết, và những thứ khác.
Thay vì lặp lại các phân tích từng dòng ở đây, tôi đã Nhận xét về từng dòng / phần của mã một cách phù hợp để bạn sẽ hiểu nó có tác dụng gì khi bạn xem qua Mã. Bạn có thể xem qua chúng.
Chuỗi sự kiện thả thính
Hãy để chúng tôi hiểu chuỗi Sự kiện, Người dùng Lựa chọn một nút, Kéo qua các nút khác trên đường đến đích cuối cùng và Giọt nó trên Target Node. Hoặc Thả nó vào vùng trống trên Điều khiển TreeView để biến nó thành Nút cấp gốc.
Khi bạn kéo một Node qua một Node-Text khác, Node-Text sẽ được đánh dấu, cho biết rằng vị trí hiện tại của bạn là trên Node này trên đường đi, cho dù bạn đi bất cứ đâu từ đây. Khi di chuyển ra khỏi Node-text, phần đánh dấu sẽ biến mất. Điều này xảy ra xuyên suốt đến Nút mục tiêu. TreeView0_OLEDragOver () Chương trình con thực hiện hành động đánh dấu này.
Khi bạn thả một nút ở đâu đó, TreeView0_OLEDragDrop () Chương trình con có quá tải. Ở đây, chúng tôi phải phân tích ý định của Người dùng và thực hiện hành động thích hợp. Thông tin sau phải được lưu và phân tích để di chuyển Node đến vị trí chính xác.
Thông tin quan trọng cần theo dõi.
-
Tham chiếu nút nguồn, Khóa nút và giá trị ParentID, Nút con, nếu có.
-
Nút đích hoặc tham chiếu vị trí, Khóa nút.
-
Nếu Mục tiêu không phải là Nút mà là vùng trống của Điều khiển TreeView, thì Nút nguồn sẽ được di chuyển vào vị trí cấp gốc.
-
Nút nguồn khi được thả trên một nút khác, nút đích sẽ trở thành nút mẹ mới của nút nguồn.
-
Nếu Source Node có con riêng của nó thì chúng cũng phải được chuyển cùng với Cha mẹ của chúng.
-
** Khi Node được kéo và thả trên Parent-Node của chính nó thì Bỏ qua hành động này.
** Ví dụ, hãy kiểm tra hình ảnh trên. Nếu chúng tôi kéo TextBox Node và thả nó vào nút mẹ Controls, hoặc kéo Điều khiển Node và thả nó vào Biểu mẫu của nút chính thì những động thái đó sẽ bị bỏ qua.
-
** Nếu Cấp gốc Nút được kéo và thả vào vùng trống, sau đó sẽ không có hành động nào được thực hiện vì nó đã là Nút cấp gốc.
Đối với tất cả các lần di chuyển hợp lệ của Node, chúng tôi cần cập nhật ParentID giá trị trường của bản ghi liên quan trên Mẫu Bảng.
Nút Thả vào Vùng trống cấp Gốc.
Trong trường hợp của mục số 3 ở trên, chúng ta phải tạo một Nút cấp gốc, có cùng Số ID của Nút nguồn, điều này không được phép. Giá trị khóa trùng lặp không được phép trong hệ thống phân cấp TreeView. Đây là khu vực duy nhất của Bộ quy tắc, nơi bạn sẽ thấy hơi khó hiểu về quy trình sau đó.
Quy trình như sau:
-
Sửa đổi Khóa nút TreeView hiện có với việc bổ sung một số văn bản bổ sung, (giả sử Khóa X5 thay đổi tới X5Empty ), để tránh xung đột Khóa trong khi tạo Nút tạm thời với Khóa ban đầu.
-
Tạo tạm thời Nút với Khóa gốc: X5.
-
Di chuyển tất cả các Nút con từ Nút nguồn, nếu có, dưới dạng các Nút con sang Nút Tạm thời.
-
Xóa nút nguồn TreeView bằng Khóa đã sửa đổi: X5Empty từ Điều khiển TreeView , nhưng bản ghi liên quan trên bảng Mẫu không được chạm vào.
-
Di chuyển tạm thời Nút bằng khóa gốc X5 cùng với con của nó đến vị trí cấp Gốc của Điều khiển TreeView.
-
Cập nhật trường ParentID của bản ghi liên quan bằng một chuỗi có độ dài bằng 0 (“”) để đánh dấu nó là Nút cấp gốc.
Tự Thử nghiệm Kéo Thả.
Bạn có thể tự mình thử một số thử nghiệm Kéo và Thả và xem nó hoạt động như thế nào. Chọn một Node, nhấp và giữ chuột trái, kéo Node và thả nó trên một Node khác hoặc thả nó vào vùng trống của TreeView Control. Khi bạn kéo Node qua Node-Text khác, nó sẽ được đánh dấu và khi bạn ra khỏi Node, vùng highlight sẽ biến mất. Node được kéo sẽ xuất hiện ở vị trí mới mà bạn đã thả nó xuống. Bạn có thể lặp lại thử nghiệm kéo thả này bằng cách chọn một Nút hoặc Nút có Trẻ em.
Dựa trên chuyển động này của các nút, ParentID của bản ghi liên quan giá trị trường sẽ được cập nhật bằng Khóa giá trị (ID) của bản ghi liên quan đến Nút đích.
Tại sao phải sử dụng quy trình điền nút hai bước?
Bây giờ, chúng ta sẽ quay lại LoadTreeView () Chương trình con, để xem lại quy trình hai bước mà chúng tôi đã áp dụng để đưa tất cả các Nút vào Điều khiển TreeView.
-
Tất cả các bản ghi trong Mẫu Ban đầu, bảng được thêm dưới dạng Nút cấp gốc, sử dụng giá trị trường ID làm Node-Key.
-
Trong lần vượt qua thứ hai của các bản ghi, nếu giá trị trường ParentID trống thì Nút đó sẽ vẫn là Nút cấp gốc mà không có thay đổi.
-
Tất cả các bản ghi liên quan đến Nút khác có Giá trị ParentID đều được di chuyển chính xác dưới Nút mẹ của nó.
Đương nhiên, câu hỏi xuất hiện, tại sao chúng ta phải làm theo cách này?
Chúng tôi sẽ làm một thí nghiệm đơn giản để làm cho câu trả lời rõ ràng mà không cần giải thích nó bằng quá nhiều từ. Bạn có thể đã tự mình thực hiện một số lần chạy thử kéo và thả các lần chạy thử và sắp xếp lại các nút, trong quá trình này đã cập nhật các giá trị ParentID của bản ghi đó với sự thay đổi. Vì vậy, chúng tôi cần đặt lại các giá trị bản ghi về trạng thái ban đầu trong Mẫu Bảng, trước khi chúng tôi bắt đầu một bản trình diễn mới.
Chúng tôi đã tạo một bản sao của Bảng Mẫu của chúng tôi trước đó, với tên Sample_bk như một bản sao lưu . Xóa Mẫu Lập bảng và tạo một bản sao từ Sample_bk với tên ban đầu: Mẫu .
Mở Bảng và xem các bản ghi và Giá trị trường ParentID của chúng. Hình ảnh mẫu của Bảng được đưa ra dưới đây:
Giá trị Trường ID là Số tự động và tất cả chúng đều theo thứ tự tuần tự và tất cả các giá trị Id là duy nhất. Quy tắc đơn giản sau đây điều chỉnh việc thêm Nút con vào Điều khiển TreeView.
Quy tắc nút con đơn giản: ParentID Giá trị trường ( Khóa chính ) trong bản ghi dự kiến rằng Nút mẹ đã tồn tại trong Điều khiển TreeView, có cùng giá trị với Node-Key (ID) .
Kiểm tra bản ghi thứ ba từ trên cùng, trong Hình ảnh Bảng ở trên. Giá trị trường ParentID là 2 và ID của bản ghi hiện tại là 3. Trong trường hợp này, bản ghi có ID 2 sẽ được thêm vào Điều khiển TreeView trước khi chúng tôi cố gắng thêm bản ghi thứ ba vào Node. Cả hai hồ sơ không nhất thiết phải ở cạnh nhau. Kiểm tra bản ghi có ID số 21, giá trị trường ParentID của nó là 12, nhỏ hơn giá trị ID bản ghi hiện tại 21.
Trong cả hai trường hợp, khi chương trình gặp Giá trị ParentID trong một bản ghi, nó sẽ giả định rằng bản ghi có giá trị ID bằng ParentID đã được thêm vào dưới dạng một Nút trong Điều khiển TreeView trong chu kỳ điền các Nút trước đó.
Giải thích cho quy trình hai bước.
Hãy để chúng tôi thử một số lần chạy thử Kéo-Thả. Tuy nhiên, trước đó, chúng tôi có một Biểu mẫu với tên frmSample, cái nào chúng tôi đã sử dụng trong Phiên hướng dẫn đầu tiên và trong đó chúng tôi đã tải tất cả các Nút TreeView trong một lần. Có, chúng tôi đã làm theo cùng một phương pháp cho đến nay và chúng tôi cần một số thay đổi từ bây giờ. Tuy nhiên, trước đó, chúng ta hãy mở biểu mẫu cũ và xem các Nút xuất hiện trên Biểu mẫu như thế nào.
-
Mở Biểu mẫu frmSample để xem màn hình TreeView trông như thế nào, với các bản ghi bảng Mẫu, được tải bằng quy tắc cũ.
-
Nếu bạn đang xem các Nút TreeView thì hãy đóng Biểu mẫu.
-
Bây giờ, hãy mở frmDragDrop Biểu mẫu. Chúng tôi đang chuẩn bị kéo và thả một Node.
-
Chọn nút với Node-Text Bảng, Nhấp và giữ nút chuột trái, kéo và thả nó trên Node, với Biểu mẫu Node-Text.
-
Bảng Nút với Trường nút con ngay lập tức của nó và các Nút con của nó được di chuyển dưới dạng Nút con trong Biểu mẫu Nút.
-
Đóng Biểu mẫu frmDragDrop và mở lại. Các nút sẽ xuất hiện chính xác, nơi bạn đã bỏ chúng, như hình ảnh được đưa ra bên dưới.
-
Bây giờ, hãy đóng Biểu mẫu frmDragDrop.
-
Mở Biểu mẫu frmSample để xem thay đổi này xuất hiện như thế nào trên Biểu mẫu này. Bạn sẽ được chào đón bằng một thông báo Lỗi, Không tìm thấy phần tử với Số lỗi:35601.
-
Chọn Nút lệnh gỡ lỗi để chuyển đến dòng Mã được đánh dấu, nơi xảy ra Lỗi.
-
Trỏ chuột vào gật đầu Tham số của phương thức Add (), nó hiển thị X3, điểm chuột trên ParentKey và nó hiển thị X7.
Nhìn vào hai giá trị tham số này, chúng ta có thể giả định rằng chúng ta đang ở trên bản ghi với giá trị ID 3 và đang cố gắng chỉ định Node này làm Node con, cho một Node khác chưa được điền vào TreeView Control, với giá trị ID 7.
-
Nhấn F5 Phím để hiển thị lại cùng một hộp thoại và Nhấp vào Kết thúc Nút lệnh để dừng Chương trình và hiển thị Biểu mẫu trên Cửa sổ Cơ sở dữ liệu. Đóng Biểu mẫu frmSample.
-
Mở Mẫu Bảng để xem sự sắp xếp của các Số ParentID, sau hành động kéo và thả của chúng ta. Bản ghi sẽ giống như hình ảnh được cung cấp bên dưới và tôi đã đánh dấu bản ghi đã kích hoạt Lỗi với giá trị ParentID 7 và hiển thị vị trí bản ghi gốc .
Theo quy trình thông thường Node điền trước đó, chúng tôi đang ở vị trí bản ghi thứ ba. Vì, các bản ghi ghi giá trị ParentID 7, Nod có giá trị ID 7 phải có trong Điều khiển TreeView. Nút có giá trị ID 7 chưa được điền vào Điều khiển TreeView, nhưng chúng tôi đang cố gắng tham chiếu đến Nút không tồn tại và điều này gây ra Lỗi.
Ngay cả khi bạn Sắp xếp các bản ghi trong trường ParentID theo thứ tự, sự sắp xếp mới của các bản ghi sẽ giống như hình dưới đây:
Bây giờ, Nút mẹ của bản ghi khác không ở vị trí mong đợi.
Do đó, trong những trường hợp này, phương pháp tải nút TreeView hai bước của chúng tôi cũng hoạt động cho cả hành động bình thường và sau khi kéo thả.
Trong bước đầu tiên, điền tất cả các bản ghi dưới dạng Nút cấp gốc trong Điều khiển TreeView bằng cách sử dụng giá trị trường ID làm Node-Key.
Bây giờ, tất cả các Nút của tất cả các bản ghi đều có sẵn trong Điều khiển TreeView. Sẽ rất dễ dàng để di chuyển chúng đến bất cứ nơi nào chúng ta muốn. It doesn’t say any of the required Node doesn’t exist in the TreeView.
In the second pass on the same set of records, the records with empty ParentID field values are untouched and allowed to remain as Root-level Nodes. In other cases moves the Node as Child-Node under its Parent Node, by updating the [Relative] Parameter of the Node with the following Statement:
Set tv.Nodes.Item(strKey).Parent = tv.Nodes.Item(strPKey)
This is what we do through the second pass on the same set of records. You may do it by resetting the Record Pointer to the first record, by executing rst.MoveFirst before the Do . . . Loop, EOF conditions and rst.MoveNext to access each record as we normally do.
Second Step in Reverse Order.
Or you may do it in reverse order. After populating all records as Root-level Nodes the Record Pointer will be beyond the last record and on the EOF position. You may reset the record pointer to the last record, by executing rst.MoveLast before the Do . . . Loop BOF check, and execute rst.MovePrevious to access each record and move the Nodes correctly under its p arent Node. But, the Nodes may load slightly differently in the placement order of Nodes.
You may try this out yourself with the above-suggested change of Code and see the result.
Download Demo Database
- Mô-đun lớp MS-Access và VBA
- Mảng đối tượng lớp VBA MS-Access
- Lớp cơ sở MS-Access và các đối tượng có nguồn gốc
- VBA Base Class and Derived Object-2
- Lớp cơ sở và các biến thể đối tượng có nguồn gốc
- MS-Access Recordset and Class Module
- Truy cập mô-đun lớp và các lớp gói
- Chuyển đổi chức năng lớp bao bọc