Is there a feature in the Listview control to shift items up and down?
Asked
Active
Viewed 2,740 times
4
-
According to title , Language is Delphi and according to the language , OS is Windows certainly. – Kermia Mar 13 '11 at 11:33
-
My apologies, I usually check the tags for these things. It is likely to be missed if you put it the end of the heading (in parentheses). – Marcelo Cantos Mar 13 '11 at 11:38
-
@Kermia: You forgot to say that you use the control in "report mode" (`ViewStyle := vsReport`). No, there is no such feature. You have to write one yourself. [This would be trivial if you used a `TListBox` instead, but I guess that you need the columns.] – Andreas Rejbrand Mar 13 '11 at 12:46
-
So , what is the solution for shift items ? would you give me an example ? – Kermia Mar 13 '11 at 13:24
-
Until I read the post I was thinking from the title that the question had to do with the key strokes `Shift-Up` and `Shift-Down`. The hyphens seem to be out of place here and very misleading. But I am not an English teacher, so I may just need to learn something new from the case. – Andriy M Mar 13 '11 at 20:22
-
@Andriy : Shift-Down is not similar to Shift **+** Down – Kermia Mar 14 '11 at 12:58
-
@Kermia: I know the latter pattern seems now to be established as the standard for specifying keystrokes, but I still remember very well the times when it wasn't so. `Shift-Up` was as correct and common a designation as `Shift+Up`. And for Control keystrokes you could additionally have `^Up`. Anyway, I've now learnt that 'shift-up' can very well be correct grammar for a noun. So the fault in being confused is all mine anyway. :) – Andriy M Mar 14 '11 at 13:21
2 Answers
4
Not having worked with TListView very much (I mostly use database grids), I took your question as a chance to learn something. The following code is the result, it is more visually oriented that David's answer. It has some limitations: it will only move the first selected item, and while it moves the item, the display for vsIcon and vsSmallIcon is strange after the move.
procedure TForm1.btnDownClick(Sender: TObject);
var
Index: integer;
temp : TListItem;
begin
// use a button that cannot get focus, such as TSpeedButton
if ListView1.Focused then
if ListView1.SelCount>0 then
begin
Index := ListView1.Selected.Index;
if Index<ListView1.Items.Count then
begin
temp := ListView1.Items.Insert(Index+2);
temp.Assign(ListView1.Items.Item[Index]);
ListView1.Items.Delete(Index);
// fix display so moved item is selected/focused
ListView1.Selected := temp;
ListView1.ItemFocused := temp;
end;
end;
end;
procedure TForm1.btnUpClick(Sender: TObject);
var
Index: integer;
temp : TListItem;
begin
// use a button that cannot get focus, such as TSpeedButton
if ListView1.Focused then
if ListView1.SelCount>0 then
begin
Index := ListView1.Selected.Index;
if Index>0 then
begin
temp := ListView1.Items.Insert(Index-1);
temp.Assign(ListView1.Items.Item[Index+1]);
ListView1.Items.Delete(Index+1);
// fix display so moved item is selected/focused
ListView1.Selected := temp;
ListView1.ItemFocused := temp;
end;
end;
end;

crefird
- 1,590
- 11
- 17
-
-
1Also it's painful to have two practically identical routines. Write one routine and make it receive a parameter to determine whether it moves up or down. – David Heffernan Mar 13 '11 at 19:12
-
1@David: I also dislike repeated code. When I try to help someone, my priority is to ensure the code works and is complete enough so it can be used with a minimum of assumptions. I felt I had achieved this goal, so I left refactoring up to the user. – crefird Mar 14 '11 at 04:02
-
The code does not work when the position is 1 in the listview. This is the flow for the code, when we click an up button the focus first shifts to the selected column -1 and then the KeyUp event handler is invoked. What is the work around for that? – siddharth taunk May 05 '16 at 09:16
3
You have two options:
- Delete them and then re-insert them at the new location.
- Use a virtual list view and move them in your data structure.
My routine for doing the first of these options is like this:
procedure TBatchTaskList.MoveTasks(const Source: array of TListItem; Target: TListItem);
var
i, InsertIndex: Integer;
begin
Assert(IsMainThread);
BeginUpdate;
Try
//work out where to move them
if Assigned(Target) then begin
InsertIndex := FListItems.IndexOf(Target);
end else begin
InsertIndex := FListItems.Count;
end;
//create new items for each moved task
for i := 0 to high(Source) do begin
SetListItemValues(
FListItems.Insert(InsertIndex+i),
TBatchTask(Source[i].Data)
);
Source[i].Data := nil;//handover ownership to the new item
end;
//set selection and focus item to give feedback about the move
for i := 0 to high(Source) do begin
FListItems[InsertIndex+i].Selected := Source[i].Selected;
end;
FBatchList.ItemFocused := FListItems[InsertIndex];
//delete the duplicate source tasks
for i := 0 to high(Source) do begin
Source[i].Delete;
end;
Finally
EndUpdate;
End;
end;
The method SetListItemValues
is used to populate the columns of the list view.
This is a perfect example of why virtual controls are so great.

David Heffernan
- 601,492
- 42
- 1,072
- 1,490
-
1`Source` contains the items to be moved. They are moved to appear before `Target`. You'll need to re-work it to fit into your code, the point of showing you the code is to express the idea rather than give you something you can use "as-is". However, if you could do a virtual list view then that would be better. – David Heffernan Mar 13 '11 at 14:03