I am still an enthusiastic user of ExplorerTreeView #1 and would be very thankful, if you could help me along with the following problem:
How can I create an array of those items, which correspond to the settings of the file and/or folder filters? After searching in the forums and several successless trials with "Explorer_BeforeInsertItem" and "Explorer_ItemLoadingSubItems" , I don't have any idea how to get this array of indexes or even better the complete path names.
Hoping you will help me once again I thank you in advance.
Which items do you want to store in an array now? Those which are displayed?
sorry for my not understandable question. I try it once again using an expample:
Setting the folder filter to "P*|Tools*" and the file filter to "*.exe" lets ExplorerTreeView
display all folders whose name starts with "P" and their subfolders whose name starts with "Tools". All displayed files have the "*.exe"-extension. So -to answer your question- the filters work well (of course "Use...Filter" is set to "True"). Now I would like to get a handle to each folder and/or file (not always both filters are used together) ETV is showing for the specified filter(s). Storing this handle in an array, collection or listbox would it make easy to jump by code to the next or previous filter result for example. To illustrate the usefullness of such a code, please imagine the following configuration:
Folders are not filtered, but the file filter is set to "*.exe" for all storage devices of the PC. In my case the filter result list is several 10.000's long and additionally all folders are shown, if all or even one logical drive is expanded by code. Having a command button by which one can jump to the next/previous filter result with or without for example skipping 50 filter results, will make it very easy to view the result of filtering or to export it or whatever your fantasy requires.
So the answer to your last question is: I want to store ALL FILTER RESULTS, indenpendend of their visibilty.
1) The control loads data on demand (when the user expands an item for the first time) and may also decide to remove data that is located in a currently collapsed sub tree. Therefore the best you could get is a list of all items that match the filters and are currently visible (it's okay if the user would have to scroll to make the items really visible).
2) The control updates itself on shell events like file creation, file deletion, file renaming, file moving and so on. Your list would get out of sync rather soon. Also the item handles may change, because the control sometimes removes an item and re-adds it. This has to do with the way how Windows notifies programs about shell events.
However, to create such a list of items that match the filters, you just need to iterate over all items using ItemGetNextItem and ItemGetFirstSubItem. For each item, check whether it's part of the file system using ItemIsPartOfFileSystem. If it's part of the file system, then the filters have been applied and the item obviously matches them (because otherwise it wouldn't be in the control).
Due to the problems described initially, it'd be better to search for the next item that matches the filters not before the user really clicks the button instead of storing the item handles of all matching items in a lookup table.
thanks a lot for your reply.
I understand your argumentation and have changed the code of the application correspondingly. Unfortunatly I failed completely, when trying to identify the filter results by iterating as supposed by you. The sub...
Code: Select all
Public Sub Next_Filter_Result(ByVal Parent_Item As Long) Dim Next_Item As Long Dim Sub_Item As Long ' Jump to Next Item Matching Folder/File Settings With ETV Next_Item = .ItemGetNextItem(Parent_Item) If .ItemIsPartOfFileSystem(Next_Item) Then .SelectedItem = Next_Item .ItemEnsureVisible (.SelectedItem) Exit Sub Else Sub_Item = .ItemGetFirstSubItem(Next_Item) Do While Sub_Item <> -1 If .ItemIsPartOfFileSystem(Sub_Item) Then .SelectedItem = Sub_Item .ItemEnsureVisible (.SelectedItem) Exit Do End If Sub_Item = .ItemGetNextItem(Sub_Item) Loop End With End Sub
In any case
I thank you for your help so fare and wish you all the best
Code: Select all
Parent 1 |- Child 1 |- Grandchild 1 |- Grandchild 2 |- Child 2 |- Child 3 |- Child 4 Parent 2
The user clicks the button. Do you want "Grandchild 2" to become selected or "Child 2"? I'll assume "Grandchild 2", so the code should look like this:
Code: Select all
Public Function Next_Filter_Result(ByVal hSelection As Long) As Boolean Dim hNext As Long With ETV hNext = .ItemGetFirstSubItem(hSelection) If hNext = 0 Then hNext = .ItemGetNextItem(hSelection) End If Do While hNext <> 0 If .ItemIsPartOfFileSystem(hNext) Then .SelectedItem = hNext .ItemEnsureVisible hNext Next_Filter_Result = True Exit Function End If If Next_Filter_Result(hNext) Then Next_Filter_Result = True Exit Function End If hNext = .ItemGetNextItem(hNext) Loop End With End Function
Thanks, same to you.aka wrote:I thank you for your help so fare and wish you all the best
thank you very, very much for the posted code. Unfortunately I don't get it working correct.
For the first trials I used for reasons of simplicity a single file filter like "*.psd". To the application I am working on I added a command button:
Private Sub Command1_Click()
Loop Until Next_Filter_Result (ETV.SelectedItem)
I expected by clicking Command1, to see the next file, matching the filter specifications, because the requirements for this are implemented in your Function
"Next_Filter_Result(hSelection)", even expanding folders and scrolling down.
But what happens is:
After selecting an arbitrary item in the tree, a click on the command button causes the next visible item to be selected, no matter if it itself or the folder and subfolders content files matching the filter specification. A second click on the button causes an "Out of stack space"-error (run-time errror 28) and the application is terminated if running in the IDE.
Error 28 is raised by the first line of the recursion in your function (signed by me with "**"):
** If Next_Filter_Result(hNext) Then **
Next_Filter_Result = True
As ExplorerTreeView is applying the filter settings to 100% correctly and you are a professional coder, there must be something wrong with my loop. And I don't have any other idea on how to use the function.
Are you willing to help me again or did I stress your nerves over the limit?
In any case I wish you all the best and like to say a warm and honest THANK's A LOT for this great component. I did not count it, but I guess in the meantime it is the one or one of the core parts in most of my hobbyist-programs.
Code: Select all
If hNext = 0 Then
Code: Select all
If hNext = -1 Then
Code: Select all
Do While hNext <> 0
Code: Select all
Do While hNext <> -1
I am really thankful for the corrections you posted. Unfortunately they brought only a small improvement: the stack overflow is avoided. All the other issues remain unchanged. Invoking the function "Next_Filter_Result" with a "Do....Until" loop as explained in the last post does nothing else than selecting the next tree item.
I think this whole matter is to complicated for me and still assume, that my
approach with this loop is wrong. So I have to give up, if you don't have the wish to continue working on the problem. What a pity!
Best regards and -even if I repeat myself- thanks a lot for your efforts
Could you please create a small sample project, that creates some files and folders and also has ExplorerTreeView and the CommandButton that triggers Next_Filter_Result integrated? With such a sample it should be easier to explain the expected behavior. You could explain it like this:
- Select folder/file abc
- Click the "Next result" button. Expected behavior: Folder/file def gets selected. Observed behavior: Folder/file xyz gets selected.
you can not imagine how happy and thankful I am about your last post.
As I don't like to create files and folders on your PC, I attached an archive "TimoSoft.zip" with some folders, subfolders and txt-files. You can store them were it is suitable for you. The demo project is zipped to "Demo.zip". It uses only a single file filter (*.txt)
The demo behaves as follows:
Selecting the "main" folder "TimoSoft" expands this folder and 2 subfolders and 2 files become visible.
After a click on "Jump to Next Filter Result" the first subfolder "TimoSoft Sub1" is selected, but not expanded as intended, altough it contains txt-files in its root and a further subfolder. Further clicks select "TimoSoft Sub2" -> "timo1.txt" -> "timo2.txt". Now you are at the last item of this folder and further click leads to a hung-up.
The summary of current state is very easy: the code always selects the next tree item without changing the level and regardless of the filter settings. If a movement a level up is required, the program does not respond anymore.
What I try to reach is:
Selecting an arbitrary item in the tree and clicking "Jump to Next Filter Result" should find the next filter result (a file OR a folder) independent of the depth of its location, expand all its parent folders, make it visible and select it. The next click should do the same, even if due to the deep level of the last selection, the code needs to jump up several tree levels and/or needs to change the logical drive.
If I have an algorithm for this, I intent to modify this that way, that it works in the other direction.
With your help, I could realize all features I wanted to have in my ExplorerTreeView-programs up to now. But this matter seems to be fare over my skills.
That's normal. The contents of "TimoSoft Sub1" won't be loaded until this item is expanded. The code that searches for the next result, of course checks only those files and folders that have been loaded into the control. Call ItemLoadSubItems to make sure the sub-items are loaded.aka wrote:After a click on "Jump to Next Filter Result" the first subfolder "TimoSoft Sub1" is selected, but not expanded as intended, altough it contains txt-files in its root and a further subfolder.
Here's the code that will call ItemLoadSubItems and search upwards if it reaches the end of a sub-tree.
Code: Select all
Private Sub Next_Filter_Result(ByVal hSelection As Long) Dim hNext As Long Dim l As Long With ETV hNext = FindNextMatchInSubTree(hSelection) If hNext = -1 Then ' try parent item's next sibling sub-tree hNext = hSelection Do hNext = .ItemGetParentItem(hNext) If hNext = 0 Then hNext = -1 ' special handling for ShowRoot = False If hNext <> -1 Then hNext = .ItemGetNextItem(hNext) If hNext = -1 Then ' we've reached the end of the tree Exit Do ElseIf ItemMatchesFilters(hNext) Then ' we've found a match Exit Do Else l = FindNextMatchInSubTree(hNext) If l <> -1 Then ' we've found a match hNext = l Exit Do End If End If Loop End If If hNext <> -1 Then ' we've found a result .SelectedItem = hNext .ItemEnsureVisible hNext End If End With End Sub ' searches the sub-items of hBaseItem *and the sibling items of hBaseItem* Private Function FindNextMatchInSubTree(hBaseItem As Long) As Long Dim hNext As Long Dim l As Long With ETV ' make sure the sub-items have been loaded .ItemLoadSubItems hBaseItem hNext = .ItemGetFirstSubItem(hBaseItem) If hNext = -1 Then ' the item does not have any sub-items, so try the next sibling item hNext = .ItemGetNextItem(hBaseItem) End If Do While hNext <> -1 ' we've found an item to investigate If ItemMatchesFilters(hNext) Then FindNextMatchInSubTree = hNext Exit Function End If ' this item doesn't match the filters, so investigate its sub-items l = FindNextMatchInSubTree(hNext) If l <> -1 Then ' a result has been found FindNextMatchInSubTree = l Exit Function End If ' no result has been found, so try the next sibling item hNext = .ItemGetNextItem(hNext) Loop End With FindNextMatchInSubTree = -1 End Function Private Function ItemMatchesFilters(hItem As Long) As Boolean With ETV If .ItemIsPartOfFileSystem(hItem) Then ' the item is of a type that can be filtered If (.ItemIsFile(hItem) And .UseFileFilters) Or (.ItemIsFolder(hItem) And .UseFolderFilters) Then ' filters are activated for this item type, so the item must match the filters ItemMatchesFilters = True End If End If End With End Function
sorry for my late reply. I did not had the time to test your last post earlier. It is a really big step forward and I owe you at least a TerraByte of thank. Unluckily, the code still is working correct only with limitations. These limitations are related to the up or down changing of the level at which the last filter result was found. An example: Selecting directly the "TimoSoft" folder I send you, everythings works as expected. On my PC this folder is located on drive "G:\", where several other folders a stored above, some of them containing filter results too (please see attached screenshot). What happens is:
1. Selecting "G:\" and clicking on "Jump to Next Filter Result" without expanding any root folders before, makes "...affiliat.txt" visible and selected. Everything is fine until "...readme.txt" is reached. If this file is selected and you try to jump to the next filter result, the code stops searching and "...readme.txt" remains the selected item.
2. Expanding the folder "Axialis ..." by clicking it in the tree and then clicking "Jump to Next Filter Result" does not cause anything. From the display of the CPU load I can see the code working for a few seconds and then stopping without finding a result. BUT selecting its subfolder "IconWorkShop Sample" and clicking on "Jump to Next Filter Result" opens "MTS-TESTS->MTS-TEST 2009_05_24" and makes "Result-Names.txt" the selected item. This is correct, because this file is the next filter result after "...readme.txt".
3. A further click again does NOT jump to and open "TimoSoft", but remains at "Result-Names.txt".
4. Selecting folder "TimoSoft" and clicking several times, not only makes all filter results in this folder visible, but jumps to the following filter results in the root of "G:\".
Of course I tried out to figure out the reason for this strange behaviour (also with other drives/folders, the result is the same), but without success. Does it make any sense to you?
IMPORTANT: On your website I read, that this project is a hobby of you and I definetely don't want to be impudent or stress your nerves. So, if you are sick and tired of this topic, do me the favour to give me a short note: Hi aka, it is enough! Last but not least, because it seems to be very likely, that my idea to change the code for "Find Next" working the other direction, will cause unsolvable problems for me too. The whole matter is very much more difficult than I expected.
Code: Select all
Private Sub Next_Filter_Result(ByVal hSelection As Long) Dim hNext As Long Dim l As Long With ETV hNext = FindNextMatchInSubTree(hSelection) If hNext = -1 Then ' try parent item's next sibling sub-tree hNext = hSelection Do hNext = .ItemGetParentItem(hNext) If hNext = 0 Then hNext = -1 ' special handling for ShowRoot = False If hNext = -1 Then ' we've reached the end of the tree Exit Do Else l = hNext hNext = .ItemGetNextItem(hNext) End If If hNext = -1 Then ' this parent does not have a sibling item hNext = l Else If ItemMatchesFilters(hNext) Then ' we've found a match Exit Do Else l = FindNextMatchInSubTree(hNext) If l <> -1 Then ' we've found a match hNext = l Exit Do End If End If End If Loop End If If hNext <> -1 Then ' we've found a result .SelectedItem = hNext .ItemEnsureVisible hNext End If End With End Sub
I have a big problem: I don't know how to express my thanks in an appropriate way!
Thank you very, very much for your last post. Now the code is perfect and finds all filter results, no matter how deep thy are located in the tree and how "fare away" they are from the last result. It's fantatstic. Using this code I can try to make it working in the other direction for "Jump to Previous Filter Result".
Once again: a warm and honest thank for the fantastic control your great support!
God bless you and all the best for you!