czardas

ListView Column Order

5 posts in this topic

#1 ·  Posted (edited)

With a listview control, when I drag a column to a new location, I can no longer loop through the columns in ascending sequence. I would like to set the new column order as an ascending numeric sequence, so that I can loop through the columns normally (after dragging). Is there a way to force the ListView control to forget/reset the order of columns. The alternative is to implement complicated loop sequences and unwieldly code, which is painful and hell to debug.

Edit: What I've tried: _GUICtrlListView_SetColumnOrderArray() moves the columns back to their original locations (that's not it :'(). I can't set the column number as an attribute - the method appears to be unsupported. It looks like I'm just going to have to track the column positions (all the time) and factor that in for every action taken which will probably add about 5% bloat to my project. Pity!

Edited by czardas

Share this post


Link to post
Share on other sites



You could use _GUICtrlListView_GetColumnOrderArray and loop through the array instead.

1 person likes this

If I posted any code, assume that code was written using the latest release version unless stated otherwise. Also, if it doesn't work on XP I can't help with that because I don't have access to XP, and I'm not going to.
Give a programmer the correct code and he can do his work for a day. Teach a programmer to debug and he can do his work for a lifetime - by Chirag Gude
How to ask questions the smart way!

I hereby grant any person the right to use any code I post, that I am the original author of, on the autoitscript.com forums, unless I've specifically stated otherwise in the code or the thread post. If you do use my code all I ask, as a courtesy, is to make note of where you got it from.

Back up and restore Windows user files _Array.au3 - Modified array functions that include support for 2D arrays.  -  ColorChooser - An add-on for SciTE that pops up a color dialog so you can select and paste a color code into a script.  -  Customizable Splashscreen GUI w/Progress Bar - Create a custom "splash screen" GUI with a progress bar and custom label.  -  _FileGetProperty - Retrieve the properties of a file  -  SciTE Toolbar - A toolbar demo for use with the SciTE editor  -  GUIRegisterMsg demo - Demo script to show how to use the Windows messages to interact with controls and your GUI.  -   Latin Square password generator

Share this post


Link to post
Share on other sites

#3 ·  Posted (edited)

Yes and that would have to be done for every change made to the listview, if dragging columns is allowed. That's where the 5% unwieldy code comes from. This is for an undo buffer I'm intending to implement, so the code is quite complicated already. It seems I have no alternative other than to than to do it your way, but I was hoping I might be able to simplify the code. I implemented a similar tracking process recently with TagSort, so I can do it using the same idea: I just hate bloat for the sake of a simple reset feature not existing (apparently). Sadly, loop code is no longer straight forward (having to always refer to a key).

On the other hand there are also some advantages to be gained from this implementation. I would just like to choose when I need to track something and when tracking is not needed. It's not a big deal.

Edited by czardas

Share this post


Link to post
Share on other sites

#4 ·  Posted (edited)

What do you mean exactly by looping through the columns in ascending sequence? Do you mean to loop through the columns from the leftmost column to the rightmost column? But this is not the usual opinion (at least not the MicroSoft opinion) of running through the columns in ascending order.

The normal way to loop through the columns in ascending sequence and the way which is supported by MicroSoft code in the header and the listview controls is to use $iSubItem from $iSubItem = 0 to $iSubItem = $iColumns - 1. Looping through the columns in this way works for a large majority of all listview commands whether the columns have been dragged to other positions or not.

$iSubItem always refers to the same column whether the columns have been rearranged or not.

If two or more columns have been dragged to other positions the sequence from $iSubItem = 0 to $iSubItem = $iColumns - 1 does of course not match the left to right order of the columns.

If you insists of looping through the columns in a left to right order (which changes every time the columns are rearranged) you need to use _GUICtrlListView_GetColumnOrderArray. But don't do that. You should use $iSubItem to loop through the columns.

_GUICtrlListView_GetSubItemRect is an example of a command in which there is a problem when columns have been rearranged. It only works for $iSubItem > 0. For $iSubItem = 0 you must use _GUICtrlListView_GetItemRect. In this example I have only used _GUICtrlListView_GetSubItemRect. That's the reason why it doesn't work for the column with $iSubItem = 0, if that column has been dragged to a new position. I'll fix it.

Conclusion: If you use $iSubItem to keep track of columns, you can usually add the $LVS_EX_HEADERDRAGDROP extended style to support rearranging of columns without changing any code at all.

Edited by LarsJ
Conclusion
1 person likes this

Share this post


Link to post
Share on other sites

#5 ·  Posted (edited)

46 minutes ago, LarsJ said:

$iSubItem always refers to the same column whether the columns have been rearranged or not.

Yes and that has merit, but it also imposes some restrictions. When we are in the business of manipulating data within a listview, writing an undo/redo buffer makes sense and presents certain challenges. The user is interacting with the control (not Microsoft) and they wouldn't be dragging columns to different positions simply for fun. To write consistent undo history code, one has to decide on the main architecture and try to stick with the same coherent method throughout. Starting with the premise that a table can always be read from top left to bottom right in an ascending sequence is a very good design concept.

Thanks for the tips, I will look at the functions you mention. I wondered about your implementation.

46 minutes ago, LarsJ said:

That's the reason why it doesn't work for the column with $iSubItem = 0, if that column has been dragged to a new position. I'll fix it.

I have already written a patch which forces the first row to always hide itself before the user gets time to interact with it. If by some fluke the user somehow manages to drag the column at lightning speed, it instantly snaps back before the user gets chance to click anywhere else. It might be possible to get around these prevention measures using a script, but that's not particularly important.

Edited by czardas

Share this post


Link to post
Share on other sites

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