We have a legacy application written in VB6 using the default Microsoft TreeView control to display hierarchical data. Since there's a lot of information in this TreeView we thought about implementing a small filter/search possibility for the users.
The first attempt was to toggle the visibility and only make nodes (and their parents) visible, that match the defined search. But that was impossible, since the default Microsoft TreeView control doesn't allow their nodes to be visible or invisible.
So the second attempt is to traverse all the nodes in the tree and ensure a node's visibility when it matches the defined search (and stop traversing). When the found node isn't the one the user is looking for he can "continue" the search and look for the next node that matches his criteria.
This works quite good so far, except for one little problem. The search doesn't work from top to bottom, since the tree is filled with data in random sort order and then sorted by setting the Sorted property of each node (legacy code). So the search is going through the randomly added nodes and the found nodes "jump" between the top level nodes (the Nodes collection of the TreeView contains all the nodes in the order they were added, not just the top level nodes and not in the order they are presented to the user).
Is there any way to get all the nodes of the tree in the order they are shown to the user? I don't like to change the legacy code that is filling the tree with data, and sorting the data before it is added to the TreeView might affect performance.
Please be aware that I'm talking about an application written in VB6, so there's no such thing as LINQ to traverse the nodes in the desired order.
Here's my searching code so far:
Private Sub cmdSearch_Click()
Dim oMatch As Node
Set oMatch = GetNextMatch
If Not (oMatch Is Nothing) Then
oMatch.EnsureVisible
oMatch.Selected = True
Me.TreeView1.SelectedItem = oMatch
Me.TreeView1.SetFocus
End If
End Sub
Private Function GetNextMatch() As Node
Dim lIndex As Long
Dim oResult As Node
For lIndex = mlLastFoundIndex + 1 To Me.TreeView1.Nodes.Count
If IsMatch(Me.TreeView1.Nodes(lIndex).Text) Then
Set oResult = Me.TreeView1.Nodes(lIndex)
mlLastFoundIndex = lIndex
Exit For
End If
Next lIndex
Set GetNextMatch = oResult
End Function
Private Sub txtSearch_Change()
mlLastFoundIndex = 0
End Sub
Rather than traversing the TreeView nodes collection by integer, you should use the Child and Next properties to accomplish what you're asking. The following code will print the children of the selected node in the order they appear in the TreeView control:
Private Sub Command3_Click()
If Not TreeView1.SelectedItem Is Nothing Then
PrintNodesInSortedOrder TreeView1.SelectedItem
End If
End Sub
Private Sub PrintNodesInSortedOrder(ParentNode As MSComctlLib.Node)
Dim Nod As MSComctlLib.Node
Set Nod = ParentNode.Child
Do While Not Nod Is Nothing
Debug.Print Nod.Text
Set Nod = Nod.Next
Loop
End Sub
Related
I want to write a VBScript, which outputs the position of a CAD part (x,y,z). The Input should be the partnumber. This is what I tried.
Sub CATMain()
dim pos(11)
for n = 1 to CATIA.Documents.Count
set Dokument = CATIA.Documents.Item(n)
for i = 1 to Dokument.product.products.Count
set InstDokument = Dokument.product.products.item(i)
If InstDokument = "my_part" Then
msgbox InstDokument.Name
InstDokument.Position.GetComponents pos
msgbox "Origin Point: X= " &pos(9) &" Y= " &pos(10) &" Z= " &pos(11)
End If
next
next
End Sub
I got an error in line 8 column 2. The object does not have the property or method.: Dokument.product
How can I solve that?
There are several problems with your code.
At the root is probably this:
set Dokument = CATIA.Documents.Item(n)
The CATIA documents collection will contain many documents which do not have windows and which the CATIA application maintains for it's own various internal purposes. So it is not assured that CATIA.Documents.Item(n) actually contains a CATProduct.
In most cases one is interested in the current active document, and it is retrieved like this:
Set Dokument = CATIA.ActiveDocument
Otherwise you can test for it
Set Dokument = CATIA.Documents.Item(n)
if typename(Dokument) = "ProductDocument" Then ...
Even after that you have problems. You are comparing the Document object to a string... and other things. Also without recursion you may never find your target instance if it is deeper then at the first level. It may also be possible that search may be a better way to find your instance then "Reading the tree".
Once you have corrected all your infrastructure errors your method for getting the transformation matrix is basically correct.
In a TreeView, how do I execute code only if a parent node's Image is 4 and any child's is 3?
If TreeView2.Nodes(ii).Image = 4 And TreeView2.Nodes(ii).Image = 3 Then.
For some reason this If TreeView2.Nodes(ii).Image = 4 checks the parent and child , I don't know why.
I am trying to use If TreeView2.Nodes(ii).parent.child.image=3 but it is not working right.
TreeView2.Nodes(ii).parent is always going to be Nothing. The top-level nodes in your TreeView don't have parents. When you use TreeView2.Nodes(ii).parent.child you are certain to get an error. Using parent.child would only be used to get the first child of the parent node which probably isn't what you are trying to do.
It sounds like you want to do the following:
Dim objRootNode As Node
Dim objChildNode As Node
Dim iRootCounter As Integer
Dim iChildCounter As Integer
For iRootCounter = 1 To TreeView1.Nodes.Count
Set objRootNode = TreeView1.Nodes(iRootCounter)
If objRootNode.Image = 4 Then
Set objChildNode = objRootNode.Child ' Gets first child
For iChildCounter = 1 To objRootNode.Children
If objChildNode.Image = 3 Then
' Write your code here
End If
Set objChildNode = objChildNode.Next ' Get next node
Next
End If
Next
Add your code where it says Write your code here. This is where parent has Image = 4 and child has Image = 3.
I need to implement a simple (but not binary) tree in Julia. Basically, each node needs to have an integer ID, and I need a convenient way to get a list of children for a node + add child to an existing node by ID.
e.g. 0->1->(2->(3,4,5),6)
where each number represents a node, I need the functions children(2) and add(7 as child of 4).
I am aware that similar tree implementations can be found for other languages, but I am pretty new to OOP/classes/data structures and not managing to "translate" them to Julia.
You didn't state whether you want the IDs to be assigned automatically as new nodes are added, or if you want to specify them when you add the children (which would involve some form of more complicated lookup).
If the IDs can be assigned, you could implement a tree structure as follows:
type TreeNode
parent::Int
children::Vector{Int}
end
type Tree
nodes::Vector{TreeNode}
end
Tree() = Tree([TreeNode(0, Vector{Int}())])
function addchild(tree::Tree, id::Int)
1 <= id <= length(tree.nodes) || throw(BoundsError(tree, id))
push!(tree.nodes, TreeNode(id, Vector{}()))
child = length(tree.nodes)
push!(tree.nodes[id].children, child)
child
end
children(tree, id) = tree.nodes[id].children
parent(tree,id) = tree.nodes[id].parent
Otherwise, you might want to use Dict{Int,TreeNode} to store the tree nodes.
I am using the following code to remove hidden/filtered lines after applying autofilters to a big sheet in VBA (big means roughly 30,000 rows):
Sub RemoveHiddenRows()
Dim oRow As Range, rng As Range
Dim myRows As Range
With Sheets("Sheet3")
Set myRows = Intersect(.Range("A:A").EntireRow, .UsedRange)
If myRows Is Nothing Then Exit Sub
End With
For Each oRow In myRows.Columns(1).Cells
If oRow.EntireRow.Hidden Then
If rng Is Nothing Then
Set rng = oRow
Else
Set rng = Union(rng, oRow)
End If
End If
Next
If Not rng Is Nothing Then rng.EntireRow.Delete
End Sub
The code comes from here: Delete Hidden/Invisible Rows after Autofilter Excel VBA
Moreover I read this thread: Speeding Up Code that Removes Hidden Rows on a Sheet
The situation: I have applied 5 different filters to a table consisting of 12 columns, therefore a lot of rows are filtered out (hidden) after the process. When I try to delete those, the code above takes a very long time. In my case I don't know if Excel was still working, so I had to force an exit. That leads to the following question:
Is there any other way than looping through all the hidden rows and deleting them?
An idea which came to my mind was to copy only the remaining unfiltered (that is non-hidden) content to a new sheet and afterwards delete the old sheet, which contains the full information. If so, how can that be done?
I don't think you need to involve another worksheet. Simply copy the rows below the existing Range.CurrentRegion property and then remove the filter and delete the original data.
Sub RemoveHiddenRows()
With Sheets("Sheet10")
With .Cells(1, 1).CurrentRegion
With .Offset(1, 0).Resize(.Rows.Count - 1, .Columns.Count)
If CBool(Application.Subtotal(103, .Columns(1))) Then
.Cells.Copy Destination:=.Cells(.Rows.Count + 1, 1)
End If
.AutoFilter
.Cells(1, 1).Resize(.Rows.Count, 1).EntireRow.Delete
End With
End With
End With
End Sub
You may also receive some good, focused help on this subject by posting on Code Review (Excel).
You can improve performance significantly with a function like this:
Option Explicit
Public Sub deleteHiddenRows(ByRef ws As Worksheet)
Dim rngData As Range, rngVisible As Range, rngHidden As Range
With ws
Set rngData = .UsedRange
With rngData
Set rngVisible = .SpecialCells(xlCellTypeVisible)
Set rngHidden = .Columns(1)
End With
End With
If Not (rngVisible Is Nothing) Then
ws.AutoFilterMode = False
' invert hidden / visible
rngHidden.Rows.Hidden = False
rngVisible.Rows.Hidden = True
' delete hidden and show visible
rngData.SpecialCells(xlCellTypeVisible).Delete
rngVisible.Rows.Hidden = False
End If
End Sub
I tested it on a file with 2 filters applied to it
The function was adapted from the code in this suggestion
I am new to this website, so I apologize if this question was asked and I could not find it.
I am trying to create a program using Visual Studio 2010 where if you select a word from either list A or B, (where lists and B are combo boxes), then it gets defined on the bottom of the screen.
The problem I am having is making a selection from a combo box with the choices for lists A and B enable/disable the appropriate list.
To phrase that better, I have a 3 combo box lists, one with choices "English and Hebrew", one titled cboEnglish, and one titled cboHebrew.
How do I make it so that if I select "English", then cboEnglish is enabled, and if I select "Hebrew", then THAT list is enabled?
I threw a bit of coding around, but all it accomplishes is that no matter what choice I pick, then the English gets enabled every time:
Private Sub English()
cboHebrew.Enabled = False
cboEnglish.Enabled = True
End Sub
Private Sub Hebrew()
cboEnglish.Enabled = False
cboHebrew.Enabled = True
End Sub
I had a draft where the choices English and Hebrew were buttons, which would make the coding really easy to do (The above code was copied from that version), but I did not really like how it looked.
I am fairly new to Visual Studio (like 1 1/2 months of use), so I apologize if this is a dumb question...
Figured it out. I ended up turning the main combo box into an integer, and defining each of the sub options to make the other boxes true/false using the same procedure as if I would have just been using 2 buttons to enable/disable them.
Not sure if this procedure is ideal, but hey, it works (for now)
Dim intLanguage As Integer
intLanguage = Me.cboLanguage.SelectedIndex
Select Case intLanguage
Case 0
English()
Case 1
Hebrew()
End Select
End Sub
Private Sub English()
'This attempts to enable English list
cboEnglish.Enabled = True
cboHebrew.Enabled = False
End Sub
Private Sub Hebrew()
'This attempts to enable English list
cboEnglish.Enabled = False
cboHebrew.Enabled = True
End Sub
End Class
I'm not into Visual Basic, but basically you should place your code into handler method. In your case it should SelectedIndexCHanged (see http://www.tutorialspoint.com/vb.net/vb.net_combobox.htm).
A simple if then else statement should work.
If combobox.optionA = selected Then
comboxBox.optionB = false
Else comobox.optionB = selected then
comboxBox.optionA = false
END if