Added: You can now drag items bewteen ListViews as long as they have the same number of columns and neither have checkboxes. Thanks to mesale0077 for suggesting it and GreenCan for all the testing.
Changed: Much of the internal UDF code has been rewritten as a result of the above.
New UDF and examples in the zip below.
Warning: There were major script-breaking changes in the release of 19 Apr 13 from previous versions of the UDF!!! Please read the change list for that release in the spoiler below if you have not already done so.
Previous versions:
Spoiler
[BUGFIX VERSION] - 22 Apr 13
Changed: _GUIListViewEx_ReadToArray returned an incorrect count when reading the content of exisiting ListViews. Sorry about that.
Warning: Major script-breaking changes in the major release of 19 Apr 13 from previous versions of the UDF!!! Please read the change list for that release in the spoiler below. [NEW VERSION] - 19 Apr 13
Warning: Major script-breaking changes to previous release versions of the UDF!!!
New and changes in this release:
Spoiler
New:
- The _GUIListViewEx_EditItem function allows for programatic selection of an item to be edited. The item does not have to be in one of the columns editable on double-clicking (see below).
- When using the _GUIListViewEx_EditItem function or after a double-click on an editable item, the user can choose to limit the edit to that single item/subitem (default) or for the {TAB} and cursor arrow keys to move the edit location around the ListView, scrolling the items into view if necessary. In the latter case, the user can choose:
- The action to take when the edit location reaches the edge of the ListView - terminate the edit process, remain at that point, or loop to the opposite edge of the ListView. The action to take can be set independently for each axis of movement.
- The action taken when {ESC} is pressed - either abandon just the current edit leaving previous edits in place or reset all edits made in the current editing session.
- The GUIListViewEx_ReadToArray function reads the current content of a ListView into an array which can then be used as a parameter in the GUIListViewEx_Init function.
Changed:
The _GUIListViewEx_Init function has several changes:
The function now takes an additional parameter to define the columns which are editable - the default setting is "all columns". The zero-based column numbers can be entered singly or as ranges e.g. "0;2;4-6;8-10;12". All ListView rows are permanently editable.
- The order of the $fImage and $iAdded parameters in the _GUIListViewEx_Init function has changed to keep the various parameters arranged in logical groups (dragging - sorting & editing).
- The $iAdded parameter has an additional option - if the ListView is editable then this option enables you to move the edit control within the same ListView by triple-clicking (a single-click to close the current edit and then a double-click to relocate it). It is always possible to swap the edit process to another ListView by double-clicking within it.
- The function to register various Windows messages has been renamed to _GUIListViewEx_MsgRegister as its previous name (_DragRegister) suggested it was only required to activate item dragging. In fact the WM_NOTIFY message needs to be registered for sorting and editing as well as dragging - the other other messages need only be registered if dragging is required.
- The function placed in the idle loop to action the edit process on a double-click has been renamed to _GUIListViewEx_Editonclick and has lost the parameter to set the editable columns - but gained a parameter which determines the edit process and {ESC} key behaviour (see the explanation above).
- The _GUIListViewEx_ReturnArray function has lost an underscore from its name to match the format of the other function names.
- Several new "Internal Use Only" functions have been added and many minor code changes have been made throughout the UDF.
Sorry about the scriptbreaking changes - I hope you feel that the added functionality to the UDF is worth the trouble of changing your scripts. Thanks to Dana for the prods to get me to do most of what he wanted. [NEW VERSION] - 14 Mar 13
New: Items and subitems can now be edited directly within the ListView. The $fSort parameter has been replaced by $iAdded:
0 = No sort or edit 1 = Sort, no edit 2 = Edit, no sort 3 = Both edit and sort
To get the editing to work the new _GUIListViewEx_Edit function must be placed in the script idle loop and the _GUIListViewEx_WM_NOTIFY_Handler function either registered or placed in an existing handler. Editing is initiated by double-clicking an item - the user can define which columns are editable via the parameter of the _GUIListViewEx_Edit function. Any use of the mouse or actioning of any other controls on the GUI abandons the editing process - normally editing is actioned by ENTER key or cancelled by ESCAPE. This change is not script-breaking as the True/False value of $fSort is mirrored by the 0/1 values of $iAdded. Thanks to johnmcloud for the idea.
Added: Just as with dragging, the _GUIListViewEx_Up/Down functions now work on multiple selections. Again thanks to johnmcloud for the push to get it working.
[BUGFIX VERSION] - 23 Feb 13
Fixed: Error adding a delimited string to an originally empty multiple column ListView created with the native function. Thanks to Garp99HasSpoken for pointing it out.
[NEW VERSION] - 26 Aug 11
New: Now works with ListViews with checkboxes. Added a parameter to _GUIListViewEx_Return_Array to return either the text or the checkbox state of the ListView. Default is to return the text as at present, so this is not script-breaking.
Fixed: Now works correctly with native ListViews with null values in the columns.
Thanks to NunoBorges for the prods to get it working as he wanted! {BUGFIX RELEASE] - 13 Jun 11 Fixed: Sort only worked in ascending order (thanks AutoitNewbie2011) - full explanation here [EX TYPO FIX RELEASE] - 25 May 11 Fixed: A couple of typos in the examples (thanks Protocoder). It seems I did not update all of them after the last update. [NEW VERSION] - 5 Feb 11 Improvements: - New parameter for _GUIListViewEx_Init to allow simple sorting of ListView on clicking the column header BugFix: - Added a missing line to one of the message handlers. Thanks WeMartiansAreFriendly. [NEW VERSION] - 3 Feb 11 Improvements: - Now x64 compatible (thanks Ascend4nt) - Now drags blocks of selected items and deletes all selected items (you can thank czardas for that as he asked for it)
Hi,
It seemed that I wanted to add, delete, edit or move items in a ListView quite often in my scripts and I got fed up with having to rewrite the code to do it each time. I also wanted to be able to drag items with the mouse. So I decided to write a UDF to make life easier and here is the result - GUIListViewEx.
If you are interested in how it works, then read this bit - if not, then skip over it:
Spoiler
The UDF creates a Global array holding the handle/ControlID of each ListView and creates a shadow array to match its contents. This shadow array will always have a counter as the first element - that way there are no problems with empty arrays. When the UDF receives an action request it amends this array and then adjusts the ListView data to match.
Only one ListView is active at any one time and the main UDF functions only affect that active ListView. To prevent appallingly difficult syntax, I decided that I would create a further shadow array for each function to amend. Once the amendments were over, this array replaces the existing shadow array and is then deleted.
The amended data within the shadow array is available at any time - the UDF removes the count element if the user has so decided. The UDF can cope with delimited or array data for later insertion - it sorts out internally how to format the inserted data to match the stored array. If no array is passed then the UDF creates a shadow array automatically - again the [0] element is always a count, but the user can choose whether to have this returned or not. One small point - if no array is passed with a multi-column ListView then the UDF will create and return a 2D array based on the number of columns.
The UDF uses only as many elements of the initial array or subsequent insert data as there are columns to fill. So you can have additional data within the array without problem. I use this feature to store the filename as well as data extracted from the file within the same array - the ListView only displays the extracted data.
The UDF is pretty easy to use:
- You start by creating a ListView (either native or UDF) and passing the returned ControlID/handle and the array you used to fill it to the _Init function of the UDF. You also indicate whether the array has a count in the [0] (or [0][0]) element and if you create an empty ListView, the UDF will still cope and will shadow any items that you insert later. If you have a ListView filled with data but no matching array, there is a function to read that data into an array for you. You can select a colour for the insert mark when dragging items if you are going to use this feature - the default is black - and decide whether to have a shadow of the dragged item follow the mouse. Finally you can set the ListView to be sortable and editable - with various options to determine how the editing process works.
- You need to register a few Windows messages, but this is a single call to the _MsgRegister function. If you already have handlers for the relevant messages, there are functions to call within these handlers instead. If you do not want to drag, then you only need the WM_NOTIFY handler loaded.
- Then you just need to call the main _Insert($vData), _Delete, _Up, and _Down functions when the appropriate button is pressed, select and drag items, or use one of the edit functions and your ListView responds automatically.
- The UDF shadows the contents of the ListView (as explained in the spoiler section above) so you can get its current state at any time with the _ReturnArray function - for example if you wanted to save the data within. Many of the functions actually return this data after each call just to help you keep track.
- When you have finished with the ListView, you should use the _Close function to clear the memory used by the UDF to shadow its contents. It is not vital, but if you use a lot of ListViews and do not do this, you could end up running out of memory.
- You can have as many ListViews as you wish on display at any one time and the same "Insert", "Delete", "Up" and "Down" buttons can be used for them all - you just have to click on the one you want to be active. The UDF also allows you to set the active ListView programatically (_SetActive) - and to determine which is currently active (_GetActive).
There are 3 example scripts to show the UDF working on native and UDF created ListViews, with single or multiple columns, and either filled or empty along with the UDF itself in this zip file:
Credit to martin (for the basic drag code which I found on the forum) and the Array UDF authors (for the basis of the array functions). GUIListViewEx.zip23.52K66 downloads
Happy for any feedback - hopefully positive!
M23
P.S. Once again the forum software is messing with one of the function names - it should read _GUIListViewEx_Edit+On+Click without the plus signs.
Edited by Melba23, 30 April 2013 - 01:27 PM.
GreenCan and mesale0077 like this
StringSize - Automatically size controls to fit text - ExtMsgBox - A user customisable replacement for MsgBox
Toast - Small GUIs which pop out of the Systray - Marquee - Scrolling tickertape GUIs
Scrollbars - Automatically sized scrollbars with a single command - GUIFrame - Subdivide GUIs into many adjustable frames
GUIExtender - Extend and retract multiple sections within a GUI - NoFocusLines - Remove the dotted focus lines from buttons, sliders, radios and checkboxes
ChooseFileFolder - Single and multiple selections from specified path tree structure - - Notify - Small notifications on the edge of the display
RecFileListToArray
- An alternative to _FileListToArray with user-defined include/exclude masks, maximum recursion level, sorting and displayed path options
GUIListViewEx - Insert, delete, move, drag and sort ListView items
That's really nice. I was just thinking it would also be nice to be able to drag multiple selections all in one hit. Perhaps that could get complicated, but it was just a thought. I'll most likely find a use for this. Great!
This looks really useful for people like me who hate working with GUI crap
However, there's a problem with the code though - it doesn't work correctly in x64 mode, even after fixing the NMHDR struct (which should be:)
Local$tagNMHDR=DllStructCreate("hwnd;uint_ptr;int;int",$lParam); NMHDR + 1st element of NMLISTVIEW
The 4th element (which is actually part of NMLISTVIEW), should be the item 'index', but always returns 0 in x64 mode. Unfortunately this results in the 1st item in the list being moved, but not the dragged one. Very odd. I haven't seen anything yet indicating why it has this behavior.. still works fine in x86 mode of course. (This is on Win 7 x64)
I do not have access to an x64 system, so if you could determine what is going wrong I would be happy to amend the code.
This x64/x86 problem seems to raise its head more and more frequently as soon as you start getting into structs. We need someone to offer a tutorial - would you be ready to take it on?
M23
StringSize - Automatically size controls to fit text - ExtMsgBox - A user customisable replacement for MsgBox
Toast - Small GUIs which pop out of the Systray - Marquee - Scrolling tickertape GUIs
Scrollbars - Automatically sized scrollbars with a single command - GUIFrame - Subdivide GUIs into many adjustable frames
GUIExtender - Extend and retract multiple sections within a GUI - NoFocusLines - Remove the dotted focus lines from buttons, sliders, radios and checkboxes
ChooseFileFolder - Single and multiple selections from specified path tree structure - - Notify - Small notifications on the edge of the display
RecFileListToArray
- An alternative to _FileListToArray with user-defined include/exclude masks, maximum recursion level, sorting and displayed path options
GUIListViewEx - Insert, delete, move, drag and sort ListView items
Okay, I figured it out. Funky thing that Windows has done here - they added a little 'buffer' between the end of the NMHDR structure and the next element in the NMLISTVIEW structure, and didn't tell anyone about it! Microsoft deserves a nice smack in the face for this.
Anyway, I've modified your function Melba23 to read as follows:
AutoIt
Func_GUIListViewEx_WM_NOTIFY_Handler($hWnd,$iMsg,$wParam,$lParam)#forceref $hWnd,$iMsg,$wParamLocal$tagNMHDR="hwnd;uint_ptr;int",$sBuf=''If@AutoItX64Then$sBuf=';int'Local$tagNMLISTVIEW=$tagNMHDR&$sBuf&";int Item;int SubItem;uint NewState;uint OldState;uint Changed;long X;long Y;lparam lParam"Local$tNMHDR=DllStructCreate($tagNMHDR,$lParam),$tListViewIf@errorThenReturnSwitchDllStructGetData($tNMHDR,3)Case-2,$LVN_COLUMNCLICK; -2 = $NM_CLICK; Check if enabled ListViewFor$i=1To$aLVEx_Data[0][0]IfDllStructGetData($tNMHDR,1)=$aLVEx_Data[$i][0]ThenExitLoopEndIfNextIf$i>$aLVEx_Data[0][0]ThenReturn; Not enabled; Set values for active ListView$aLVEx_Data[0][1]=$i$hGLVEx_Handle=$aLVEx_Data[$i][0]$hGLVEx_CID=$aLVEx_Data[$i][1]$aLVEx_Array=$aLVEx_Data[$i][2]Case$LVN_BEGINDRAG; Check if registered ListViewFor$i=1To$aLVEx_Data[0][0]IfDllStructGetData($tNMHDR,1)=$aLVEx_Data[$i][0]ThenExitLoopEndIfNextIf$i>$aLVEx_Data[0][0]ThenReturn; Not registered; Set values for ListView$aLVEx_Data[0][1]=$i$hGLVEx_Handle=$aLVEx_Data[$i][0]$hGLVEx_CID=$aLVEx_Data[$i][1]; Copy array for manipulation$aLVEx_Array=$aLVEx_Data[$i][2]; Check if Native or UDF and set focusIf$hGLVEx_CIDThenGUICtrlSetState($hGLVEx_CID,256); $GUI_FOCUSElse_WinAPI_SetFocus($hGLVEx_Handle)EndIf$tListView=DllStructCreate($tagNMLISTVIEW,$lParam)#cs
ConsoleWrite("ListView items: Item: "& DllStructGetData($tListView,'Item')& _
", SubItem: "&DllStructGetData($tListView,'SubItem')& _
", NewState: "&DllStructGetData($tListView,'NewState')& _
", OldState: "&DllStructGetData($tListView,'OldState')& _
", Changed: "&DllStructGetData($tListView,'Changed')& _
", X: "&DllStructGetData($tListView,'X')& _
", Y: "&DllStructGetData($tListView,'Y')& _
", lParam: "&DllStructGetData($tListView,'lParam')& @LF)
#ce; Store index of dragged item$iLVEx_Dragged_Index=DllStructGetData($tListView,'Item'); Item; Set flag$fLVEx_Dragging=True; Remove highlighting from item_GUICtrlListView_SetItemSelected($hGLVEx_Handle,$iLVEx_Dragged_Index,False)EndSwitchEndFunc;==>_GUIListViewEx_WM_NOTIFY_Handler
I've filled in the whole NMLISTVIEW structure for you, which provides additional information that may or may not be of interest to you. In testing on Win7 x64, all the elements are returning fine (per the ConsoleWrite() I inserted).
You can of course remove all the extra info and modifications I made, but you'll need to retain that buffer for x64 systems, and then pull the 'Item' element by name rather than number.
If anyone is running Vista x64, I'd like to confirm that the above altered function works on that O/S as well, as I don't currently have a build to test that on (I'm assuming its an x64 issue, but there's always a chance that its a Win7 x64 issue, I suppose)
Oh, and Melba23 - sorry, no tutorial from me lol. For the most part, stick to the structure datatypes found on MSDN and you'll be fine (this is one exception however where its not the case). Also, Jon did a thread on this -> Structs and DllCall under x64.
Melba, hmm.. seems I should have realized this earlier - the NMHDR is where there's an issue. The third element should be 'int_ptr'.
The problem with that, and what initially threw me, is the negative numbers in the Case statement would have to be positive since int_ptr is a 64-bit value, and the negative numbers refer to a 32-bit-sized integer. But we can force them to be negative with BitAND..
Change those two lines, and your UDF is fixed. One interesting thing though - the NMLISTVIEW structure will tell you the SubItem you are 'moving'. Not sure if that actually can be used tor any good though, since moving just sub-items would be a bit more complex and confusing.
I do take exception to the "fixed" bit though - I woudl have preferred "x64 compatible".
Pity about the tutorial though.
M23
Edited by Melba23, 02 February 2011 - 07:48 PM.
StringSize - Automatically size controls to fit text - ExtMsgBox - A user customisable replacement for MsgBox
Toast - Small GUIs which pop out of the Systray - Marquee - Scrolling tickertape GUIs
Scrollbars - Automatically sized scrollbars with a single command - GUIFrame - Subdivide GUIs into many adjustable frames
GUIExtender - Extend and retract multiple sections within a GUI - NoFocusLines - Remove the dotted focus lines from buttons, sliders, radios and checkboxes
ChooseFileFolder - Single and multiple selections from specified path tree structure - - Notify - Small notifications on the edge of the display
RecFileListToArray
- An alternative to _FileListToArray with user-defined include/exclude masks, maximum recursion level, sorting and displayed path options
GUIListViewEx - Insert, delete, move, drag and sort ListView items
- Now drags blocks of selected items and deletes all selected items (you can thank czardas for that as he asked for it )
New UDF and zip in first post
M23
StringSize - Automatically size controls to fit text - ExtMsgBox - A user customisable replacement for MsgBox
Toast - Small GUIs which pop out of the Systray - Marquee - Scrolling tickertape GUIs
Scrollbars - Automatically sized scrollbars with a single command - GUIFrame - Subdivide GUIs into many adjustable frames
GUIExtender - Extend and retract multiple sections within a GUI - NoFocusLines - Remove the dotted focus lines from buttons, sliders, radios and checkboxes
ChooseFileFolder - Single and multiple selections from specified path tree structure - - Notify - Small notifications on the edge of the display
RecFileListToArray
- An alternative to _FileListToArray with user-defined include/exclude masks, maximum recursion level, sorting and displayed path options
GUIListViewEx - Insert, delete, move, drag and sort ListView items
Nice Example. Plus its good to see the x64 issue with $tagNMHDR has been rectified in this version. I am a little bit reluctant to start changing the ListView includes to work with x64!
Good work Melba. Just curious - is the multiple-item-move supposed to work with contiguous selected items only? Only reason I ask is because doing multiple selection using 'Ctrl-click' works only when the items are bunched together - any other items selected remain where they were.
For example, if items #1-3 and item #6 selected, then dragged. Only items 1-3 will be moved. Item #6 stays in the same spot.
Otherwise - very nice job. One day I might use it.. though I think I stopped futzing around with ListViews because I wanted 'sort' and 'insert-into-sorted' list functions, but was too lazy to do the work
I also considered the idea of dragging gapped selections, but it's not clear to me how it should work or why it is needed. I can think of two viable alternatives: either you queue the items that are not selected and insert them between the gaps, or you could collapse the gaps in the selection during the drag. While dragging a contiguous selection in one hit can save a lot of time, I don't see the same benefit with a non-continguous selection, except under very rare circumstances. Although, it would be a pretty neat trick.
You are correct - it will only move a consecutive block of selections - although you can drag any of the items within the section to move it. I could not think of a sensible logic to move the other selected items as well. And anyway it looked as if any solution would require far too much coding!
Mat,
GUITreeViewEx.....I will have to think about that one a bit.
Thanks for the separator tip - you will see it is now implemented.
M23
Edited by Melba23, 04 February 2011 - 02:00 PM.
StringSize - Automatically size controls to fit text - ExtMsgBox - A user customisable replacement for MsgBox
Toast - Small GUIs which pop out of the Systray - Marquee - Scrolling tickertape GUIs
Scrollbars - Automatically sized scrollbars with a single command - GUIFrame - Subdivide GUIs into many adjustable frames
GUIExtender - Extend and retract multiple sections within a GUI - NoFocusLines - Remove the dotted focus lines from buttons, sliders, radios and checkboxes
ChooseFileFolder - Single and multiple selections from specified path tree structure - - Notify - Small notifications on the edge of the display
RecFileListToArray
- An alternative to _FileListToArray with user-defined include/exclude masks, maximum recursion level, sorting and displayed path options
GUIListViewEx - Insert, delete, move, drag and sort ListView items
1. Drag a few list view items (on the first listview)
2. Click elsewhere on the GUI a couple of times (not a button or listview)
* Column 0 text disapears
* Console says
-- Inserting at LV Index: 10
-- Inserting at LV Index: 11
--etc
4. Drag a few more items a couple times
5. ...
(944) : ==> Variable used without being declared.:
_GUIListViewEx_Array_Insert($aLVEx_Array, $iGLVExInsert_Index + 1, $aInsertData[$i])
_GUIListViewEx_Array_Insert($aLVEx_Array, $iGLVExInsert_Index + 1, ^ ERROR
Tried this with the second list view and Steps 1 and 2 follow immediatly with an hardcrash error
I also got these errors but I don't recall what I did to cause them
==> Subscript used with non-Array variable.:
_GUICtrlListView_SetItemText($hGLVEx_Handle, $i, $aLVEx_Array[$i + 1])
_GUICtrlListView_SetItemText($hGLVEx_Handle, $i, $aLVEx_Array^ ERROR
==> Array variable subscript badly formatted.:
Local $aInsertData[$iMultipleItems + 1]
Local $aInsertData[^ ERROR
Windows XP SP3, AutoIt 3.3.6.0
[Edit: No hard crash ]
Edited by WeMartiansAreFriendly, 05 February 2011 - 01:49 AM.
Thank you for that - I can reproduce them all and I know what the problem is.
I somehow missed a check line in one of the message handlers so it reacted all the time and not just when dragging.
New UDF and zip in first post. Thanks again.
M23
StringSize - Automatically size controls to fit text - ExtMsgBox - A user customisable replacement for MsgBox
Toast - Small GUIs which pop out of the Systray - Marquee - Scrolling tickertape GUIs
Scrollbars - Automatically sized scrollbars with a single command - GUIFrame - Subdivide GUIs into many adjustable frames
GUIExtender - Extend and retract multiple sections within a GUI - NoFocusLines - Remove the dotted focus lines from buttons, sliders, radios and checkboxes
ChooseFileFolder - Single and multiple selections from specified path tree structure - - Notify - Small notifications on the edge of the display
RecFileListToArray
- An alternative to _FileListToArray with user-defined include/exclude masks, maximum recursion level, sorting and displayed path options
GUIListViewEx - Insert, delete, move, drag and sort ListView items
I need more code than that to give you a sensible answer - I would suggest posting the whole script.
When you post your code please use Code tags. Put [autoit] before and [/autoit] after your posted code.
M23
StringSize - Automatically size controls to fit text - ExtMsgBox - A user customisable replacement for MsgBox
Toast - Small GUIs which pop out of the Systray - Marquee - Scrolling tickertape GUIs
Scrollbars - Automatically sized scrollbars with a single command - GUIFrame - Subdivide GUIs into many adjustable frames
GUIExtender - Extend and retract multiple sections within a GUI - NoFocusLines - Remove the dotted focus lines from buttons, sliders, radios and checkboxes
ChooseFileFolder - Single and multiple selections from specified path tree structure - - Notify - Small notifications on the edge of the display
RecFileListToArray
- An alternative to _FileListToArray with user-defined include/exclude masks, maximum recursion level, sorting and displayed path options
GUIListViewEx - Insert, delete, move, drag and sort ListView items