Em có bài này đã tìm hiểu lâu rồi mà chưa có thuật toán nào gỡ rối được mong các thầy gỡ rối giùm
Chủ đê cộng tổng các giá trị Child trong cấp Parent, thực hiện hiển thị ra trên Treeview.
em biết treeview là rất khó nên nhờ các thầy giúp em với. Thankssssss
Em có bài này đã tìm hiểu lâu rồi mà chưa có thuật toán nào gỡ rối được mong các thầy gỡ rối giùm
Chủ đê cộng tổng các giá trị Child trong cấp Parent, thực hiện hiển thị ra trên Treeview.
em biết treeview là rất khó nên nhờ các thầy giúp em với. Thankssssss
Em có bài này đã tìm hiểu lâu rồi mà chưa có thuật toán nào gỡ rối được mong các thầy gỡ rối giùm
Chủ đê cộng tổng các giá trị Child trong cấp Parent, thực hiện hiển thị ra trên Treeview.
em biết treeview là rất khó nên nhờ các thầy giúp em với. Thankssssss
Cảm ơn bác siwtom đã góp ý. Tất nhiên là cộng tổng cả các cấp con vô cùng (chút chít .....).
Bác huuthang_bd , đây là thuật toán treeview, và dữ liệu phân xưởng, tổ 1 tổ 2 chỉ là mẫu thôi, nếu trong trường hợp khác ta thêm nhiều cấp con, cháu chút chít,.... thì có cộng tổng được ở tất cả các cấp con bên trong đó không?
Cảm ơn bác siwtom đã góp ý. Tất nhiên là cộng tổng cả các cấp con vô cùng (chút chít .....).
Bác huuthang_bd , đây là thuật toán treeview, và dữ liệu phân xưởng, tổ 1 tổ 2 chỉ là mẫu thôi, nếu trong trường hợp khác ta thêm nhiều cấp con, cháu chút chít,.... thì có cộng tổng được ở tất cả các cấp con bên trong đó không?
Cảm ơn bác siwtom đã góp ý. Tất nhiên là cộng tổng cả các cấp con vô cùng (chút chít .....).
Bác huuthang_bd , đây là thuật toán treeview, và dữ liệu phân xưởng, tổ 1 tổ 2 chỉ là mẫu thôi, nếu trong trường hợp khác ta thêm nhiều cấp con, cháu chút chít,.... thì có cộng tổng được ở tất cả các cấp con bên trong đó không?
Tôi lường được trường hợp này nên hỏi cho khỏi mất công.
Thuật toán không có gì khó. Bạn có "ông bố" nào đấy, ông bố đầu chắc lấy trong NodeClick. Có thì đọc được giá trị của ông bố. Sau đó tìm con đầu lòng của ông bố - node.child. Sau đó tìm con tiếp theo, tức em của child kia - node.Next (node là nói về Object node của TreeView - ở đây là tìm child.Next). Tìm tới khi hết con thì thôi (Nothing). Muốn tìm cháu, chắt chít thì khi tìm được "vị" nào thì coi vị đó là "ông bố" mới và lặp lại thuật toán. Để đơn giản thì dùng đệ quy.
Về giá trị gán cho node: node có một thuộc tính để người dùng sử dụng tùy theo nhu cầu của mình - đó là Tag. Vậy:
1. Khi bạn thêm node thì gán luôn giá trị cho nó vào Tag, tức
Mã:
Set node = ...
[COLOR=#ff0000]node.Tag = ...[/COLOR]
2.
Mã:
Sub SumAll(node As MSComctlLib.node, tong As Long)
Dim child As MSComctlLib.node
' cộng giá trị của "bố"
tong = tong + node.Tag
' tìm con đầu lòng
Set child = node.child
Do While Not child Is Nothing
' coi con là "bố" khác và lặp lại thuật toán cho ổng
SumAll child, tong
' tìm con tiếp theo, tức em của con trước
Set child = child.Next
Loop
End Sub
Private Sub TreeView1_NodeClick(ByVal node As MSComctlLib.node)
Dim tong As Long
TextBox1.Text = node.Text
TextBox2.Text = node.Tag
tong = 0
SumAll node, tong
TextBox3.Text = tong
End Sub
' cộng giá trị của "bố" tong = tong + node.Tag
vì kiểu của tong là Long, mà Node.tag nó trả về kiểu String hay arr gì đó.
Em thử dùng Val(node.tag) thì ko thấy nó báo lỗi nhưng không nhân được kết quả.
Nhưng rất tuyệt vời là Code củaBác huuthang_bd em thêm các cấp Child thì thấy OK , mà đúng ý em đang muốn hỏi, tuyệt quá.
Cảm ơn bác huuthang_bd , vô cùng tận.
À em đã Kiểm tra lại thì có 1 vấn đề : Nó chỉ cộng được tổng cấp Parent trong cùng thoi, cấp ngoài thì nó không cộng được tức là chỉ cộng được 1 cấp thôi. Có cách nào cộng được tất cả các cấp Child không nhỉ? kể cả cộng tổng của cả phân xưởng luôn ấy.
Nhờ các Bác tham mưu giúm nhé!
' cộng giá trị của "bố" tong = tong + node.Tag
vì kiểu của tong là Long, mà Node.tag nó trả về kiểu String hay arr gì đó.
Em thử dùng Val(node.tag) thì ko thấy nó báo lỗi nhưng không nhân được kết quả.
Private Sub TreeView1_NodeClick(ByVal Node As MSComctlLib.Node)
Dim Tong As Long, i As Long
Me.TextBox1.Text = Node.Text
Me.TextBox2.Text = ArrTemp(Dic.Item(Node.Key), 5)
Tong = ArrTemp(Dic.Item(Node.Key), 5)
On Error GoTo Show
Set Node = Node.Child
Tong = Tong + ArrTemp(Dic.Item(Node.Key), 5)
For i = 2 To Node.Parent.Children
Set Node = Node.Next
Tong = Tong + ArrTemp(Dic.Item(Node.Key), 5)
Next
Show:
Me.TextBox3.Text = Tong
End Sub
Trước tiên rất xin lỗi vì đã nói rằng Code của bác bị lỗi. Em đã nghiên cứu về mặt thuật toán thấy vòng lặp đã duyệt được hết các giá trị Node nhưng quả thực trên máy của em nó vẫn chư chạy được, em gửi file đã ghép Code của bác với dữ liệu bác test dùm em với nhé.
và trên thực tế thông báo lỗi và file em nhờ bác siwtom xem giùm
Trước tiên rất xin lỗi vì đã nói rằng Code của bác bị lỗi. Em đã nghiên cứu về mặt thuật toán thấy vòng lặp đã duyệt được hết các giá trị Node nhưng quả thực trên máy của em nó vẫn chư chạy được, em gửi file đã ghép Code của bác với dữ liệu bác test dùm em với nhé.
và trên thực tế thông báo lỗi và file em nhờ bác siwtom xem giùm
Xin bổ sung thêm một số chia sẻ cho vấn đề đã trình bày trong bài viết. Tôi xin phép bác huuthang sửa đoạn code của bác. Trên thực tế ta không cần phải dùng đến đối tượng Dictionary trong bài toán này. Khi nghiên cứu kỹ lý do phải dùng Dic của bác, tôi thấy có lẽ không nhất thiết phải phức tạp hóa như vậy.
Lý thuyết cơ bản của yêu cầu chỉ là:
1. Dựa vào cấu trúc dữ liệu của tác giả, xây dựng thuật toán đưa chúng vào cấu trúc TreeView;
2. Căn cứ vào việc lựa chọn đối tượng, tính toán tổng sản lượng tạo ra bởi các đối tượng con của đối tượng hiện tại đang lựa chọn.
Tuy nhiên, khi xem xét vào cấu trúc dữ liệu và cách đặt vấn đề, tôi thấy có một vài điểm yếu
1. Liên quan đến xây dựng cấu trúc cây dữ liệu
Thông thường để lưu quản lý dữ liệu dạng cây, người ta cần có cách nào đó để tránh phải xác định thứ tự các nhánh cha/con một cách thủ công.
Với trường hợp hiện tại, bạn đang phải sắp xếp một cách thủ công và rất dễ xảy ra lỗi cấu trúc.
Thuật toán dựng cây của bác Huuthang là xét tuần tự dựa vào thiết lập dữ liệu đã có sẵn. Nếu có lỗi về sắp xếp: ví dụ, một đối tượng con tham chiếu đến đối tượng cha lại chưa được thêm vào cây (nằm ở các dòng sau) thì sẽ phát sinh lỗi.
Chính vì thế, trong thực tế, người ta có 2 cách tiếp cận xây dựng CSDL cho cây
1. Xác lập mối liên quan cha con theo dạng dữ liệu có thể sắp xếp được ví dụ 01 và 01.01 ...vv (giống cách của bạn nhưng theo một quy tắc định trước trong đó nếu sắp xếp theo trường Key thì sẽ luôn luôn có các Node ở cấp gốc đứng đầu).
2. Dùng biện pháp quét ngang qua toàn cây với 2 trường thuộc tính trái/phải của một node trong đó node gốc sẽ có trường trái bắt đầu từ 1 và phải kết thúc bằng tổng sô nodex2.
Cách này hiện nay được dùng khá nhiều do không phải sử dụng thuật toán đệ quy khi tải dữ liệu. Tuy nhiên, mỗi khi có sự thêm/bớt node thì người ta phải xây dựng lại thuộc tính trái/phải của cấu trúc cây (Link tham khảo này khá thú vị http://www.sitepoint.com/hierarchical-data-database-2/). Về chủ đề này, nếu các bạn quan tâm, tôi có thể viết hoặc lược dịch một số bài viết hay để tham khảo.
2. Liên quan đến tính toán số liệu
Căn cứ vào bài viết, có thể thấy rõ, số liệu chỉ nằm ở các phần tử cấp thấp nhất (nói khác hơn, chỉ các công nhân mới tạo ra sản lượng). Vì thế, trong bài viết của bạn, mặc dù tôi đã viết lại thuật toán tính tổng nhưng với các đối tượng cha, do chúng có thuộc tính QTY là rỗng vì thế bất kể ở cấp Cha nào, thuật toán sẽ tự tìm kiếm các đối tượng có số liệu ở cấp thấp nhấp để tính.
PHP:
Private Sub TreeView1_NodeClick(ByVal Node As MSComctlLib.Node)
' Tôi sửa lại một chút code của bác Huuthang để cho đơn giản
Dim Tong As Long, i As Long
TextBox1.Text = Node.Text
TextBox2.Text = Node.Tag
TextBox3.Text = GetTotal(Node)
End Sub
Private Function GetTotal(ByVal Node As Node) As Single
' Hàm này để tính tổng tất cả các node con
Dim i As Integer, nodX As Node
If Node.Children <> 0 Then 'Nếu Node này có node con
Set nodX = Node.Child 'Lấy Node con đầu tiên
For i = 1 To Node.Children 'Duyệt qua từng node
GetTotal = GetTotal + GetTotal(nodX)
Set nodX = nodX.Next 'Gán cho Node con tiếp theo
Next
Else
GetTotal = Val(Node.Tag)
End If
End Function
Private Sub CreateTreeView()
'Nhập vào Treeview
Dim ArrTemp As Variant, i As Long, Node As Node
UserForm1.TreeView1.Nodes.Clear
' Tạo ra một mảng từ vùng dữ liệu
ArrTemp = Range([A65536].End(xlUp), [A2]).Resize(, 6).Value
For i = 1 To UBound(ArrTemp, 1)
With TreeView1
If ArrTemp(i, 3) = "" Then
Set Node = .Nodes.Add(, , ArrTemp(i, 2), ArrTemp(i, 1), ArrTemp(i, 4))
Else
Set Node = .Nodes.Add(ArrTemp(i, 3), tvwChild, ArrTemp(i, 2), ArrTemp(i, 1), ArrTemp(i, 4))
End If
' Gán giá trị của Node vào thuộc tính Tag để tính toán cho dễ
Node.Tag = ArrTemp(i, 5)
Node.Expanded = True
End With
Next
End Sub
Quên mất, tôi có sửa tên thủ tục Familytree.... thành CreateTree vì thế bạn copy code trên vào chắc sẽ không chạy được. Bạn xem lại file đính kèm trong bài viết trước sẽ thấy nhé.
Thank bác paulsteigel. Em test OK rồi. chạy ổn. File bác đính kèm thì ko chạy vì trong Form bị xóa mất cái Treeview nhưng thêm cái treeview vào chạy Tít. Cảm ơn các bác rất rất nhiều.
Em cũng cảm ơn bác siwtom, bác huuthang đã tham gia góp ý xây dựng cho bài tập này của em.
Chào bạn! .Mình cũng mới học VBA. Mình cũng đang thắc mắc một số vấn đề về treeview:
bạn có thể chỉ giúp mình làm nút Showtreeview được không, thankssssssssssssss