Jump to content

Recommended Posts

Posted

@WildByDesign
Thank you very much for the praise, I am glad you like it :).

And thanks for finding the bug, I fixed it. It was a missing check for $sPath="" in __TreeListExplorer__OpenPath when checking if the path is a file (and then splitting it), that did overwrite the $sSelect to empty.

I also checked, if it is possible to select multiple files/folders, which is working with ListViews and not causing any problems. So I added that to the example. (It looks like it is not possible to enable multiselection for TreeViews, if I did not overlook something... Only thing I saw was enabling checkboxes).

Posted

@Kanashius You are very welcome. I am happy to help anytime I can. And thank you as well.

I was able to drop 2.6.0 right into my current app without any modifications and it worked great, with a minor bug that I will describe below. Also, the addition of retrieving file type icons was a nice added touch as well.

The bug can be reproduced in your example app. Using the keyboard to go up and down through all of the drive letters (only drive letters), the selection works 100%. However, if you use only mouse clicks to click through all of the drive letters (only drive letters), it will stop updating the selection and only show the previous selection. It seems to work by mouse click maybe 20% of the time. No issue with keyboard selection though. And this bug only affects the root drive letters.

Posted

Well and I did a little change again :D

I liked, that the treeview did not expand, when clicking a folder, but that also means, that the listview is not changed to that folder... I fixed that now. When clicking a folder in the treeview, the folder is opened (becomes the current folder), but not expanded in the treeview.

While doing that, I thought, it would be nice to have an Input Control to show the path and to be able to open folders. Well, thats now possible. Simply use __TreeListExplorer_AddView($hSystem, $idInput) and it will be added. When pressing enter in that Input control, the folder is opened by the system.

Posted (edited)

@WildByDesign

I think it was working, but you sometimes clicked at the icon... Can happen, if the text is so short. And I think, the Icon should count as a click as well, not just the text, so I adjusted that. Another possibility would be "empty" drives. I do have two empty CD drives and they do not trigger a select. I am not sure, if that is a bug though... They aren't valid folders (which is why they are filtered out)... they cannot be opened. One could argue, if they should be shown at all 🤔.

I also fixed a smaller issue I introduced with v2.7.0, where the click at a TreeView item no longer triggered a selection change event. It now does.

Edited by Kanashius
Posted
10 minutes ago, Kanashius said:

And I think, the Icon should count as a click as well, not just the text, so I adjusted that.

I think you are right about this. I was likely clicking on the icon many of those times.

I will spend a lot of time testing 2.7.1 tonight and put it through some good testing.

I do have a question for you regarding the icon imagelist. The line:

Local $hImageList = _GUIImageList_Create(16, 16, 5, 1)

The 16 pixels is very dependent on the users' DPI scaling setting. In my app, I get the DPI and store it in a variable and replace the 16 values with the variable and it works really well. But I am wondering, is this something that should (or could) be done within the UDF, or should I just keep doing that part myself?

Posted

Regarding the DPI scaling: To my knowledge, in AutoIt the DPI-Scaling is not happening by default, instead it must be enabled specifically ( DPI-Scaling ). Normally the gui is scaled as a whole, I think.
That is probably, why I cannot really see a difference at my screens.
Additionally, I have no idea, how that would work when moving the gui from one monitor to another (I have different scaling per screen, because 2 are FHD and one is 4k)... All images would have to be rescaled every time and all views reloaded?

I think I will not open that can of worms :D.
But I added it as a parameter for __TreeListExplorer_StartUp, so you can pass it there, without changing the UDF. That could be useful, when someone is changing the fontsize as well.

Posted
11 hours ago, Kanashius said:

I think I will not open that can of worms :D.
But I added it as a parameter for __TreeListExplorer_StartUp, so you can pass it there, without changing the UDF. That could be useful, when someone is changing the fontsize as well.

That is a smart decision, I realize now. I think by adding the parameter to pass the icon size is perfect and it worked well in my case.

I have a question for you. I started to really enjoy using the $sSelected variable in your recent updates because it made it so that I didn't have to parse the paths anymore for part of my UI. However, I realized that the variable would be blank on treeview expand and treeview click. It only worked on keyboard selection, which is understandable.

So I added __TreeListExplorer__OpenAndSelectLast($iSystem, $sPath) into two Case sections as follows:

Case $TVE_EXPAND
    If Not __TreeListExplorer__IsViewUpdating($hView, $__TreeListExplorer__Status_ExpandTree) Then
        __TreeListExplorer__SetViewUpdating($hView, True, $__TreeListExplorer__Status_ExpandTree)
        Local $sPath = __TreeListExplorer__TreeViewGetRelPath($iSystem, $hView, $hItem)
        __TreeListExplorer__HandleViewCallback($hView, "sCallbackLoading", "$sCallbackLoading", $sPath, True)
        _GUICtrlTreeView_BeginUpdate($hView)
        __TreeListExplorer__ExpandTreeitem($hView, $hItem)
        __TreeListExplorer__OpenPath($iSystem, __TreeListExplorer__GetCurrentPath($iSystem) & _GUICtrlTreeView_GetText($hView, $hItem))
        __TreeListExplorer__OpenAndSelectLast($iSystem, $sPath)
        _GUICtrlTreeView_EndUpdate($hView)
        __TreeListExplorer__HandleViewCallback($hView, "sCallbackLoading", "$sCallbackLoading", $sPath, False)
        __TreeListExplorer__SetViewUpdating($hView, False, $__TreeListExplorer__Status_ExpandTree)
    EndIf

Case $NM_CLICK
    Local $iX =_WinAPI_GetMousePosX(True, $hView)
    Local $iY =_WinAPI_GetMousePosY(True, $hView)
    Local $hItem =_GUICtrlTreeView_HitTestItem($hView, $iX, $iY)
    Local $iHitStat =_GUICtrlTreeView_HitTest($hView, $iX, $iY)
    If $hItem<>0 And (BitAND($iHitStat, 4) Or BitAND($iHitStat, 2)) Then
        Local $sPath = __TreeListExplorer__TreeViewGetRelPath($iSystem, $hView, $hItem)
        __TreeListExplorer__OpenPath($iSystem, $sPath, "", True)
        __TreeListExplorer__OpenAndSelectLast($iSystem, $sPath)
        __TreeListExplorer__HandleViewCallback($hView, "sCallbackClick", "$sCallbackOnClick", $hItem)
    EndIf

I had to add them at the right spot, otherwise it wouldn't work. But as I have it here, it works perfectly. I get the correct $sSelected variable when the treeview expands and also on mouse click (and already previously on keyboard). I haven't spotted any issues because of this change and it always seems to give me the correct info that I needed.

So my question is: Do you see any issues that could be caused because of these two changes?

Posted (edited)
Quote

Do you see any issues that could be caused because of these two changes?

If you do that, you can remove the __TreeListExplorer__OpenPath in the line before, because that is overwritten.
The problem with that is not the TreeView, but an attached ListView. If you click on a folder in a TreeView, then you expect that folder to be opened in the ListView. So it makes sense, to define, that if an item is selected in the TreeView, it becomes the currently opened folder. So with the latest changes, I did that and instead prevented the folder from being expanded, when it is clicked.

I reworked the complete selection internally. It should now behave like you expect. Only thing to be careful about is the selection callback. The selection callback for a treeview sends the last folder as selected, but __TreeListExplorer_GetSelected will not reflect that.
So to be safe, you can always combine __TreeListExplorer_GetPath($hSystem) & __TreeListExplorer_GetSelected($hSystem) or for the callback $sFolder & $sSelect. That will always reflect the currently selected item in the treeview. And __TreeListExplorer__GetPathAndLast($sPath) will give you the path and the last folder/filename for that (e.g. ["C:\Exampe\", "coolFile.txt"]).

Additionally it is now possible to navigate listviews with the the keyboard (Up/Down/Enter).

I also found an interesting bug, that is probably AutoIt intern. If you click on an item in a ListView, that has a custom icon, the index of that icon will be send as an Event, so GuiGetMsg returns that index => the control with the id of that icon index will be triggered. This also happens, if I disable my internal message handling (WinProc/KeyProc), so it is probably a problem for all ListViews with custom icons.
So I suppress the AutoIt internal handling of MouseClick for ListViews now...

Edited by Kanashius
Posted (edited)

@Kanashius Sorry for the delay in feedback on 2.8.0. I had integrated 2.7.2 into my current project and everything was working perfectly. I have been struggling with 2.8.0 and have several parts of my project failing that I can't figure out.

I am still quite new to AutoIt, so whenever you do an update I try my best to understand the changes between each version. But I am stuck. So I will try to explain and I am sure you will spot my problem right away.

Func _selectCallback($hSystem, $sRoot, $sFolder, $sSelected)
        $newItem = $sRoot&$sFolder&$sSelected
        $displaySelected = $sSelected
        treeviewChangesfunc()
    EndFunc

With 2.7.2, I was getting everything I needed from _selectCallback. $newItem was the full path to folder or file which I would then obtain ACL information for. $displaySelected was simply just getting the currently selected folder name or file name for part of the UI.

My issue seems to be only with files. Everything to do with folders is working properly. Every attempt that I have tried to do to get the selected filename has failed.

I will try again with __TreeListExplorer__GetPathAndLast($sPath) but I don't know exactly where to put it.

EDIT: The Example script with 2.8.0 also doesn't show the selected filenames anymore like it did with previous versions.

Edited by WildByDesign
Posted

@WildByDesign

Thanks again, thats a bug I overlooked when changing to many things at once 😅

Line 1669: 
From: __TreeListExplorer__GetPathAndLast(__TreeListExplorer__GetCurrentPath($iSystem))
To: __TreeListExplorer__GetPathAndLast(__TreeListExplorer__GetCurrentPath($iSystem) & __TreeListExplorer__GetSelected($iSystem))

So it is fixed in v2.8.1 :)

Depending on treeviewChangesfunc(), you may want to add a check, if the folder/selection changed. If it did not change you should not have to do anything. This may prevent unnessesary calls => better performance
Assuming $newItem still contains the old item from the last call ( see what I did there? 😋 ), you can simply do this:

Func _selectCallback($hSystem, $sRoot, $sFolder, $sSelected)
    Local $sNewPath = $sRoot&$sFolder&$sSelected
    If $newItem<>$sNewPath Then
        $newItem = $sRoot&$sFolder&$sSelected
        $displaySelected = $sSelected
        treeviewChangesfunc()
    EndIf
EndFunc

I would also an encourage you to try not to use global variables (or as few as possible). That makes the code a lot easier to understand, without having to keep all the global variables in the back of your head and to remember where they change...
I would also take a look at the notation, to now, how to name variables: https://www.autoitscript.com/autoit3/docs/intro/lang_variables.htm#VariableNaming

An example how that would look like for the short example you provided (with some comments):

ConsoleWrite(@crlf & @crlf & "-------------------" & @crlf)
_selectCallback(1, "C:\Users\", "Default", "desktop.ini")
_selectCallback(1, "C:\Users\", "Default", "desktop.ini")
_selectCallback(1, "C:\Users\", "Default", "tmp.txt")
_selectCallback(1, "C:\Users\", "Default", "tmp.txt")
_selectCallback(1, "C:\Users\", "Default", "desktop.ini")
ConsoleWrite("-------------------" & @crlf & @crlf)




Func _selectCallback($hSystem, $sRoot, $sFolder, $sSelected)
    Local Static $sOldPath = -1 ; Static makes a variable "global", but only available in this function
    Local $sNewPath = $sRoot&$sFolder&$sSelected ; combine to path
    ConsoleWrite(@TAB&"Select: "&$sOldPath&" >> "&$sNewPath&@crlf)
    If $sOldPath<>$sNewPath Then ; check if the path changed
        $sOldPath = $sNewPath ; save the path to be available for the next call of this function
        _OnTreeViewChange($sNewPath, $sSelected)
    EndIf
EndFunc


Func _onTreeViewChange($sPath, $sSelected) ; your old treeviewChangesfunc
    ConsoleWrite("TreeView change: "&$sPath&" Selected: "&$sSelected&@crlf)
EndFunc

 

Posted
10 hours ago, Kanashius said:

Thanks again, thats a bug I overlooked when changing to many things at once 😅

You're welcome. Thank you for the quick fix. I thought I was losing my mind on that one. 🙂

Everything with your UDF is working perfectly and as you would expect. And everything with 2.8.1 is working cohesively with my project.

10 hours ago, Kanashius said:

Depending on treeviewChangesfunc(), you may want to add a check, if the folder/selection changed. If it did not change you should not have to do anything. This may prevent unnessesary calls => better performance
Assuming $newItem still contains the old item from the last call ( see what I did there? 😋 ), you can simply do this:

In my treeviewChangesfunc(), I have a very simple If $newItem <> $oldItem Then $oldItem = $newItem. But your suggestion would prevent it from even getting to treeviewChangesfunc() so yours is even more efficient and cleaner as well. So I will switch to your example. Thank you.

10 hours ago, Kanashius said:

I would also an encourage you to try not to use global variables (or as few as possible).

Yes, I agree. This is something that I need and want to learn more about. I definitely need to read up more on (and practice) passing variables from function to function without using Global variables and also making functions that return variables that I need. This is an area that I still don't feel very confident in quite yet.

Your examples (with comments) are absolutely valuable. That helps a lot.

Posted (edited)

@Kanashius I just found what might be another small regression with all of the recent changes.

Back around 2.5.0, when you have a file selected in treeview and performed a reload with __TreeListExplorer_Reload($hTLESystemRight, True) , it would refresh all of the drives and the treeview would still have that same file selected.

With 2.8.1, performing a reload with __TreeListExplorer_Reload($hTLESystemRight, True) while having a file selected in treeview, it still refreshes all of the drives but the problem is that the treeview selection changes (from the selected file) to the previous folder and therefore collapses that folder.

EDIT: Reloading while a folder is selected is not an issue. It just seems to happen when a file is selected when reloading.

Edited by WildByDesign
Posted (edited)

The reason for that is pretty simple: Opening a folder in a TreeView only selects the last folder and does not expand it. The File/Folder selection is only done, if the open folder is expanded. When reloading, the open folder is not expanded anymore and thus, the file is not selected.

I implemented it this way, because if you have a ListView, you can select Folders/Files there and they will only be selected, when the folder is expanded in the TreeView. This prevents a folder from being expanded, just because something in the ListView got selected...

I will think about checking, if the folder was expanded before reloading and then expanding it again... Would be more consistent...
But then I would probably have to check that for all folders to be consistent again 🤔

Edited by Kanashius
Posted

To be honest, I am not even sure if it should remain selected or not. I just wanted to point out the difference in functionality from the Example script between 2.5 and 2.8.

Remaining selected after reload could also cause complications if that file were to be deleted before reload.

Posted

I rewrote the TreeView expanding/loading/updating/... It no longer deletes all TreeItem childs, when reloading. Instead they are only deleted/added/updated. This is probably a little less performant, but with C:\Windows\System32 expanded, it was not noticable and still pretty much instant. I thought it would be slower, which is why I did not do that in the first play.
This keeps the current state of the already existing items (like being expanded).
I also added the "This PC" entry when the root is empty. This makes everyhting more consistent and removes a lot of edge cases. (Multiple root elements, root element is part of the open folder,... which needed special handling,...).

Quote

Remaining selected after reload could also cause complications if that file were to be deleted before reload

That was already the case for any part of the path (like folders,...).

Posted

I like the addition of This PC. There seems to be a bunch of weird things visible in the Example with 2.9.0:

- most of the drives (left and right treeviews) show a visible 'HasChilds' entry at the bottom that seems to disappear after a few clicks

- the Test button seems to disappear once you open any directory

Still testing but that is what seems to consistently happen each time.

 

Posted
49 minutes ago, Kanashius said:

Did you change anything in the UDF?

No, I haven't modified the UDF or the Example. I always create a new folder each version to test the example and save each version separately so that I always have orginals.

image.thumb.png.f6582e810c96269555ffb0d54a33a9c5.png

This is each folder looks like originally. But after clicking into another folder, the HasChilds will disappear. They are only there at the start.

Posted

After some more testing of the example, it seems that the HasChilds shows up maybe 20% of the time. For example, run the example 10 times in a row and see if it shows up for you. It's not consistent like I first thought. But random and around 20% of the time.

Posted

I could not replicate that... I tried like 30 times. On my Win10 PC and my Win11 Laptop...

I noticed, that they are at the bottom, so I added something to remove anything below the last added item, when filling the treeview... maybe that fixes your problem.
I will put it here, until you confirm if it works, before adding it to the main post.

TreeListExplorer.au3

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...