Solved

Moving TListView items loses "checked" setting in other items

Posted on 2014-07-17
4
348 Views
Last Modified: 2014-07-20
Hello Experts... I'm working with a TListView that has checkboxes enabled and in "vsReport" style. My goal is to be able to double-click on any item and have that item "swap places" with whatever item is in the top of the ListView (ie. Item[0]). Googling around, I found some code on this website that I'm using:

http://stackoverflow.com/questions/6213945/delphi-listview-move-items-up-down-with-buttons

It outlines an "ExchangeItems" procedure that looked to be just what I needed. I added only a few lines to it for my specific needs . Normally it would swap Item(i) and Item[j]... I wanted it to swap  Item[0] and Item[j]. And also to correctly swap the value of the "checked" property too. Here's my code:

procedure TForm1.ExchangeItems(lv: TListView; const j: Integer);
var
  tempLI: TListItem;
  Item0CheckedState, ItemJCheckedState : Boolean;
begin
  lv.Items.BeginUpdate;
  try
    Item0CheckedState:= lv.Items.Item[0].Checked;
    ItemJCheckedState:= lv.Items.Item[j].Checked;
    tempLI := TListItem.Create(lv.Items);
    tempLI.Assign(lv.Items.Item[0]);
    lv.Items.Item[0].Assign(lv.Items.Item[j]);
    lv.Items.Item[0].Checked:= ItemJCheckedState;
    lv.Items.Item[j].Assign(tempLI);
    lv.Items.Item[j].Checked:= Item0CheckedState;
    tempLI.Free;
  finally
    lv.Items.EndUpdate
  end;
end;  // procedure ExchangeItems

Open in new window



Simple enough i thought... and seemed logically sound. I tried a small test - I added only 3 items to my ListView: Thing0, Thing1, and Thing2. I put a checkmark in the middle item Thing1.  and left the other two unchecked. Then I double-clicked on the bottom Thing2 item. The procedure does indeed "swap" the two items and their corresponding "checked" values correctly, but it unexpectedly and unwantedly turns the Checked setting of item Thing1 (...which was TRUE) to FALSE.  I put tracing statements after every line of the code in that procedure to find out where this was occurring, and it appears the culprit is this line:

    tempLI.Assign(lv.Items.Item[0]);

Immediately after this line, the "checked" value of Thing1 got switched to FALSE, for some reason. This one is driving me bonkers trying to figure out. Does anyone have some insight please?

Thanks!
    Shawn
0
Comment
Question by:shawn857
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 2
  • 2
4 Comments
 
LVL 27

Expert Comment

by:Sinisa Vuk
ID: 40203959
no need to complicate.....just use insert at specific index and assigned values (checked is included):
procedure TForm1.ListView1DblClick(Sender: TObject);
var
  itm: TListItem;
begin
  itm := ListView1.Selected;
  if Assigned(itm) then
    ExchangeItems(ListView1, itm.Index);
end;

procedure TForm1.ExchangeItems(lv: TListView; const j: Integer);
var
  tempLI, newLI: TListItem;
begin
  if j =0 then Exit;

  lv.Items.BeginUpdate;
  try
    tempLI := lv.Items.Item[j];
    newLI := lv.Items.Insert(0);
    newLI.Assign(tempLI);
    tempLI.Free;
  finally
    lv.Items.EndUpdate
  end;
end;

Open in new window

0
 

Author Comment

by:shawn857
ID: 40205829
Thanks Sinisa! Your ListView1DblClick procedure works perfectly, but your suggested code for procedure ExchangeItems does not work right. For my example of 3 items:

Thing0
Thing1  (this one is checked)
Thing2

It will result in:

Thing2
Thing0
Thing1  (this one remains checked... correct)

Instead of Thing2 and Thing0 swapping places (as I would like), Thing2 appears to have just "bumped down" Thing0 one notch below.  Do you see?

Thanks!
   Shawn
0
 
LVL 27

Accepted Solution

by:
Sinisa Vuk earned 500 total points
ID: 40206713
Sorry, I miss that swap....here is new procedure...plain old "swap buckets":

procedure TForm1.ExchangeItems(lv: TListView; const j: Integer);
var
  newLI: TListItem;
begin
  if j = 0 then Exit;

  lv.Items.BeginUpdate;
  try
    //temp item
    newLI := lv.Items.Add;
    //keep old j
    newLI.Assign(lv.Items.Item[j]);
    //new j
    lv.Items.Item[j].Assign(lv.Items.Item[0]);
    //new 0
    lv.Items.Item[0].Assign(newLI);
    //remove temp item
    newLI.Free;
  finally
    lv.Items.EndUpdate
  end;
end;

Open in new window

0
 

Author Closing Comment

by:shawn857
ID: 40207557
Success!! Thank you Sinisa!

Cheers
    Shawn
0

Featured Post

Independent Software Vendors: We Want Your Opinion

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Objective: - This article will help user in how to convert their numeric value become words. How to use 1. You can copy this code in your Unit as function 2. than you can perform your function by type this code The Code   (CODE) The Im…
Introduction I have seen many questions in this Delphi topic area where queries in threads are needed or suggested. I know bumped into a similar need. This article will address some of the concepts when dealing with a multithreaded delphi database…
There are cases when e.g. an IT administrator wants to have full access and view into selected mailboxes on Exchange server, directly from his own email account in Outlook or Outlook Web Access. This proves useful when for example administrator want…
In this brief tutorial Pawel from AdRem Software explains how you can quickly find out which services are running on your network, or what are the IP addresses of servers responsible for each service. Software used is freeware NetCrunch Tools (https…
Suggested Courses
Course of the Month5 days, 19 hours left to enroll

627 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question