-2

I have a List View with eight columns and a popup menu. [ScreenShot]image

I have this code which is work great to copy into clipboard all items and sub items when a row or all rows selected.

procedure TForm1.CopyURL1Click(Sender: TObject);
var 
  lv : TbsSkinListView;
  s : string;
  c,f,k : integer;

begin
  lv := bsSkinListView1;
  Clipboard.Clear;
  s := '';

  for f := 0 to lv.Items.Count - 1 do
  begin     
     k := 0;
     if lv.Items[f].Selected then
     begin
       s := s + Format('%s : %s, ',[lv.Columns[k].Caption, lv.Items[f].Caption]);
       for c := 0 to lv.Items[f].SubItems.Count - 1 do
       begin
         Inc(k);
         s := s + Format('%s : %s, ',[lv.Columns[k].Caption, lv.Items[f].SubItems[c]]);
       end;
      SetLength(s, Length(s) - 2);
      s := s + #$D#$A;
    end;      
  end;
  clipboard.AsText := s;
end;

What i need is I'd like to copy only the caption of column one (column "Title") with it's sub items [0], and copy the column 8 caption (column "URL") with it's sub items [7] into clipboard, when a row or all rows selected.

Also sometime sub items[7] is empty, and it shouldn't get index out of bounds (7) error message.

From my screenshot above, when i copy the 1st row, the result should return like this

Title : 10 Things You Didn't Know...  URL :   <=== this is an empty sub items [7]

when 2nd row copied:

Title : 10 Things You Didn't Know...  URL : http://www.example.com

All rows selected :

Title : 10 Things You Didn't Know...  URL : 
Title : 10 Things You Didn't Know...  URL : http://www.example.com

i have try this link but it doesn't meet or not work as i need. I'm using Delphi XE 4. How do i achieve this? Any help would be highly appreciated.

Community
  • 1
  • 1
Ling Loeng
  • 128
  • 2
  • 9
  • What prevents you from copying what you want? – Sertac Akyuz Nov 02 '16 at 19:00
  • @SertacAkyuz using the code above, i get all sub items copied, like this: `No : 2, Title : 10 Things You Didn't Know..., Quality : webm 256x144, Size : 3.09 MB, % : 100.0%, Speed : 568.05 KB/s, ETA : 00:00 , status : Done...!, URL : https://www.example.com` while i need only `Title : 10 Things You Didn't Know... URL : https://www.example.com` – Ling Loeng Nov 02 '16 at 19:04
  • 1
    You have to write code that does what you want. You might want to start reading about the [if statement](http://docwiki.embarcadero.com/RADStudio/en/Declarations_and_Statements_(Delphi)#If_Statements). – Sertac Akyuz Nov 02 '16 at 19:08
  • I have learn about if statement. But as a beginner, i can't figure out it properly. i have tried write like this `for f := 0 to lv.Items.Count - 1 do begin` `if lv.Items[f].Selected then` `s := 'Title :' + lv.Items[f].SubItems[0] + 'URL : ' +` `lv.Items[f].SubItems[7]; ` . Seems does work but i get index out of bonds when subitems[7] is empty – Ling Loeng Nov 02 '16 at 19:18
  • That is where you would use an 'if'. Test if there is a subitems[7], if there is proceed with the line you pasted, if not, use `s := 'Title :' + lv.Items[f].SubItems[0] + 'URL :` – Sertac Akyuz Nov 02 '16 at 19:21
  • i tried your suggestion with this simple code like this: `if lv.items[f].Selected then begin` `if lv.items[f].SubItems[7] <> '' then` `s := 'Title : ' + lv.Items[f].SubItems[0] + ' URL : ' +` `lv.Items[f].SubItems[7]` `else` `s := 'Title : ' + lv.Items[f].SubItems[0] + ' URL : ';` `end;` `Clipboard.AsText := s;`. Stil i get index out of bonds sub items 7 when its' empty. Can you help me, please? I'm really stuck with that – Ling Loeng Nov 02 '16 at 19:55
  • subitems[7] is not empty, it doesn't exist. – Sertac Akyuz Nov 02 '16 at 20:11
  • @SertacAkyuz I didn't know before if it doesn't exist. Now i can figure out it to works. Many thanks. :) – Ling Loeng Nov 02 '16 at 20:33

1 Answers1

4

Your clipboard text contains all of the column values because you are looping through all of the TListItem.SubItems values. If you don't want all of the values, simply don't loop anymore. Just access the specific items you want.

Try something more like this:

procedure TForm1.CopyURL1Click(Sender: TObject);
var 
  s : string;
  item: TListItem;
begin
  s := '';
  item := bsSkinListView1.GetNextItem(nil, sdAll, [isSelected]);
  while item <> nil do
  begin     
    s := s + Format('Title : %s, ', [item.Caption]);
    if item.SubItems.Count > 7 then
      s := s + Format('URL : %s, ', [item.SubItems[7]]);
    s[Length(s)-1] := #$D;
    s[Length(s)]   := #$A;
    item := bsSkinListView1.GetNextItem(item, sdAll, [isSelected]);
  end;
  Clipboard.Open;
  try
    Clipboard.Clear;
    Clipboard.AsText := s;
  finally
    Clipboard.Close;
  end;
end;

With that said, an alternative option would be to use the TListView in virtual mode instead (OwnerData=True), where you store all of your data in a separate list. Then you can access your data list directly without having to touch the TListView at all. For example:

type
  PMyData = ^TMyData;
  TMyData = record
    Selected: Boolean;
    Title: String;
    ...
    URL: string;
  end;

  TForm1 = class(TForm)
    ...
  private
    MyData: TList;
    ...
  end;

...

procedure TForm1.FormCreate(Sender: TObject);
begin
  MyData := TList.Create;
end;

procedure TForm1.FormDestroy(Sender: TObject);
var
  I: Integer;
begin
  for I := 0 to MyData.Count-1 do
    Dispose(PMyData(MyData[I]));
  MyData.Free;
end;

procedure TForm1.bsSkinListView1Data(Sender: TObject; Item: TListItem);
var
  Data: PMyData;
begin
  Data := PMyData(MyData[Item.Index]);
  Item.Caption := Data.Title;
  Item.SubItems.Add(...);
  ...
  Item.SubItems.Add(Data.URL);
  Item.Data := Data;
end;

procedure TForm1.TForm1.bsSkinListView1SelectItem(Sender: TObject; Item: TListItem; Selected: Boolean);
var
  I: Integer;
begin
  if Item <> nil then
    Item.Selected := Selected
  else
  begin
    for I := 0 to MyData.Count-1 do
      PMyData(MyData[I]).Selected := Selected;
  end;
end;

procedure TForm1.TForm1.bsSkinListView1DataStateChange(Sender: TObject; StartIndex, EndIndex: Integer; OldState, NewState: TItemStates);
var
  I: Integer;
begin
  if (OldState * [isSelected]) <> (NewState * [isSelected]) then
  begin
    for I := StartIndex to EndIndex do
      PMyData(MyData[I]).Selected := (isSelected in NewState);
  end;
end;

procedure TForm1.AddItem1Click(Sender: TObject);
var
  Data: PMyData;
begin
  New(Data);
  try
    Data.Selected := False;
    Data.Title := ...;
    ...
    Data.URL := ...;
    MyData.Add(Data);
  except
    Dispose(Data);
    raise;
  end;
  bsSkinListView1.Items.Count := MyData.Count;
end;

procedure TForm1.CopyURL1Click(Sender: TObject);
var 
  s : string;
  Data: PMyData;
  I: Integer;
begin
  s := '';
  for I := 0 to MyData.Count-1 do
  begin
    Data := PMyData(MyData[I]);
    if Data.Selected then
    begin     
      s := s + Format('Title : %s, ', [Data.Title]);
      if item.URL <> '' then
        s := s + Format('URL : %s, ', [Data.URL]);
      s[Length(s)-1] := #$D;
      s[Length(s)]   := #$A;
    end;
  end;
  Clipboard.Open;
  try
    Clipboard.Clear;
    Clipboard.AsText := s;
  finally
    Clipboard.Close;
  end;
end;
Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770