If I get time I will test tonight. From what I have read it appears you can load the imagelist at runtime. So I will try that.
Dim path As String
Dim file As String
Dim PathAndFile As String
Dim oFile As Variant
Dim oFiles As Collection
path = CurrentProject.path & "\" & "bitmaps"
Set oFiles = AllFiles(path)
For Each oFile In oFiles
PathAndFile = path & "\" & oFile
Me.imageListNodes.listimages.Add , Replace(oFile, ".bmp", ""), LoadPicture(PathAndFile)
'Debug.Print Me.imageListNodes.listimages.Count
'Debug.Print PathAndFile
Next oFile
End Sub
Public Function AllFiles(ByVal FullPath As String) _
As Collection
'***************************************************
'PURPOSE: Returns all files in a folder using
'the FileSystemObject
'PARAMETER: FullPath = FullPath to folder for
'which you want all files
'************************************************
Dim oFs As New FileSystemObject
Dim sAns As New Collection
Dim oFolder As Folder
Dim oFile As file
Dim lElement As Long
If oFs.FolderExists(FullPath) Then
Set oFolder = oFs.GetFolder(FullPath)
For Each oFile In oFolder.Files
If Right(oFile.Name, 4) = ".bmp" Then
sAns.Add oFile.Name
End If
Next
End If
'Debug.Print sAns.Count
Set AllFiles = sAns
ErrHandler:
Set oFs = Nothing
Set oFolder = Nothing
Set oFile = Nothing
End Function
shouldn't this be in code samples, say?
I love recursion. One problem with vba is that there is no true pointer data type which makes it hard to represent recursive objects.
It's pretty elegant, for example, to walk a family tree with a handful of lines of code.
fwiw, I constructed a program to play draughts/checkers using a recursive minimax algorithm as my final year degree project. Very educational, if not ever so fast.
This dynamically loads the images from the folder at runtime.
For the demo purpose I used a folder in the same folder as the application called "Bitmaps". FYI, previously I had to get new bitmaps the ones you provided for some reason would not load. In an application you would probably want a system setting in some table to allow the user to browse and store the default path.
Code:Dim path As String Dim file As String Dim PathAndFile As String Dim oFile As Variant Dim oFiles As Collection path = CurrentProject.path & "\" & "bitmaps" Set oFiles = AllFiles(path) For Each oFile In oFiles PathAndFile = path & "\" & oFile Me.imageListNodes.listimages.Add , Replace(oFile, ".bmp", ""), LoadPicture(PathAndFile) 'Debug.Print Me.imageListNodes.listimages.Count 'Debug.Print PathAndFile Next oFile End Sub Public Function AllFiles(ByVal FullPath As String) _ As Collection '*************************************************** 'PURPOSE: Returns all files in a folder using 'the FileSystemObject 'PARAMETER: FullPath = FullPath to folder for 'which you want all files '************************************************ Dim oFs As New FileSystemObject Dim sAns As New Collection Dim oFolder As Folder Dim oFile As file Dim lElement As Long If oFs.FolderExists(FullPath) Then Set oFolder = oFs.GetFolder(FullPath) For Each oFile In oFolder.Files If Right(oFile.Name, 4) = ".bmp" Then sAns.Add oFile.Name End If Next End If 'Debug.Print sAns.Count Set AllFiles = sAns ErrHandler: Set oFs = Nothing Set oFolder = Nothing Set oFile = Nothing End Function
Already figured it out, as I predicted it would work. Just add a single child node per level and expand the next lower levenel on the tree view expand event. I am going to make it an optional parameter to load full or load light. That way can compare to see if it makes a big difference, which I expect will be.@MajP
I just checked both an xml file, and a folder structure, and they seem to preload all the nodes. Maybe you need a different mechanism to load your 50K nodes.
Public Sub addBranch(rsTree As DAO.Recordset, parentIDValue As Variant, identifier)
On Error GoTo errLable
Dim strCriteria As String
Dim bk As String
Dim currentID As Variant
Dim currentText As String
Dim currentNode As Node
Dim ParentNode As Node
Dim strKey As String
strCriteria = mParentIDfield & " = '" & parentIDValue & "'"
'Since it is not a root node must determine the parent node. All node keys are "ID " & the primary key
Set ParentNode = Me.Nodes(parentIDValue)
'MsgBox strCriteria
rsTree.FindFirst (strCriteria)
'MsgBox strCriteria
Do Until rsTree.NoMatch
currentID = rsTree.Fields(mIDfield)
currentText = rsTree.Fields(mNodeTextField)
identifier = rsTree.Fields(mTypeIdentifierField)
Set currentNode = Me.Nodes.Add(ParentNode, tvwChild, currentID, currentText)
currentNode.Tag = identifier
bk = rsTree.Bookmark
Call addBranch(rsTree, currentID, identifier)
rsTree.Bookmark = bk
rsTree.FindNext (strCriteria)
Loop
Exit Sub
errLable:
MsgBox Err.Number & " " & Err.Description & " In addBranch"
If MsgBox("Do you want to exit the loop?", vbYesNo, "Error In Loop") = vbYes Then
Exit Sub
Else
Resume Next
End If
End Sub
Public Sub addLiteBranch(rsTree As DAO.Recordset, parentIDValue As Variant, identifier)
On Error GoTo errLable
Dim strCriteria As String
Dim bk As String
Dim currentID As Variant
Dim currentText As String
Dim currentNode As Node
Dim ParentNode As Node
Dim strKey As String
strCriteria = mParentIDfield & " = '" & parentIDValue & "'"
'Since it is not a root node must determine the parent node. All node keys are "ID " & the primary key
Set ParentNode = Me.Nodes(parentIDValue)
rsTree.FindFirst (strCriteria)
'Only going to get the top node
If Not rsTree.NoMatch Then
currentID = rsTree.Fields(mIDfield)
currentText = rsTree.Fields(mNodeTextField)
identifier = rsTree.Fields(mTypeIdentifierField)
Set currentNode = Me.Nodes.Add(ParentNode, tvwChild, currentID, currentText)
currentNode.Tag = identifier
bk = rsTree.Bookmark
Call addLiteBranch(rsTree, currentID, identifier)
rsTree.Bookmark = bk
rsTree.FindNext (strCriteria)
End If
Exit Sub
errLable:
MsgBox Err.Number & " " & Err.Description & " In addBranch"
If MsgBox("Do you want to exit the loop?", vbYesNo, "Error In Loop") = vbYes Then
Exit Sub
Else
Resume Next
End If
End Sub
Private Sub mTVW_Expand(ByVal Node As MSComctlLib.Node)
'Flush out any remaining nodes in this expanded level and liteload child level
Dim strCriteria As String
Dim bk As String
Dim currentID As Variant
Dim currentText As String
Dim currentNode As Node
Dim ParentNode As Node
Dim currentIdentifier As String
Dim rsTree As DAO.Recordset
Debug.Print Node.Text & " " & "Selected Node"
Set rsTree = Me.Recordset
strCriteria = mParentIDfield & " = '" & Node.key & "'"
rsTree.FindFirst (strCriteria)
Debug.Print strCriteria
If rsTree.NoMatch Then
MsgBox "There is no record with a Parent ID of " & Node.key
End If
if node.children > 1 then exit sub
Do Until rsTree.NoMatch
currentID = rsTree.Fields(mIDfield)
Debug.Print currentID & " current"
currentText = rsTree.Fields(mNodeTextField)
currentIdentifier = rsTree.Fields(mTypeIdentifierField)
If Node.Child.key = currentID Then
Node.Child.Tag = currentIdentifier
RaiseEvent ExpandedBranch(Node.Child)
Else
Set currentNode = mTVW.Nodes.Add(Node.key, tvwChild, currentID, currentText)
currentNode.Tag = currentIdentifier
RaiseEvent ExpandedBranch(currentNode)
bk = rsTree.Bookmark
Call addLiteBranch(rsTree, currentID, currentIdentifier)
End If
rsTree.Bookmark = bk
rsTree.FindNext (strCriteria)
Loop
End Sub
1. Load from common query
2. Drag and drop of nodes and update database
3. Add, edit delete record in database and update tree
4. Delete, edit node and update database
5. Move node up and down in level and update sort order
6. Apply icons to specific records
7. dynamically load icons from folder at runtime
8 Right click on node with pop up command bar
9. Right click off node with different command bar
10. Expand and collapse tree and branch
11. Node selected to synch subform
12. Node double click to add, edit, delete
13. Auto level creates outline numbering
14. Save sort
15. Autolevel levels
16. Full load of nodes or light load and add nodes when expanded
I forgot a reference to Office for the command bars. I will repost.
@dgreen
I updated the previous file.
1) I added my class module for a Find as you Type combo box which you will find far superior. You will want this for your library because it turns any combobox into a FAYT with one line of code. It also works much better because it handles up and down arrow keys. I instantiate on the load event.
2) The problem with the combo is an issue with a light load. It is searching for a node that is not loaded yet. As I said you probably want to use a full load (modify the initialize method) and will not have an issue, but I put in error checking to explain it. Try now. Pick something like 1.2 (second level) and you will get the error message. Expand that node and then try it.
3) I fixed the select node feature so that it is highlighted blue and not the faint highlight. The method is drop highlight.
All those other features are your specifics, and not necessary for demonstrating the Treeview features. Unless you have additional features or code, do whatever you want formatting and removing of other objects. Some of those buttons are for demo purposes and can be removed because of the combo. You may no longer want to capture the double click event since you can do that off the right click.