Link to home
Start Free TrialLog in
Avatar of esk
esk

asked on

copy,paste in listview

i know this is difficult question.
But i tray ask.

my Delphi app has listview and i want to be able to copy paste
( with multivalues to )

ESK
Avatar of rwilson032697
rwilson032697

Listening
also listening..
Go to bed Barry!!!! :-)
if the list view is to contain files i can point you toward:
http://ftp/d20free/fileexpl.zip
copy/cut/paste etc..
for not files then i have no idea...
Hmm, for Copy you could create a TStringList. Loop through all items. For those that are selected construct a string like [Caption]#9[SubItem1]#9[SubItem2]...
and add it to the TStringList.
Then throw it on the clipboard like so:
Clipboard.Text := StringList.Text;

For paste, create a TStringList and set it's Text property from the clipboard. Now loop through the stringlist, and add a TListItem for each item in the stringlist. You'll need Pos, Copy and Delete to pull each string apart.

Cheers,
Phil.
Avatar of esk

ASKER

example? philipleighs
It all depends on what needs to be copied and pasted and which customers will also use the clipboard data. If only the listview is producer and consumer then pick any comfortable format (Phil has suggested one). In any other case you should go with the default formats like CF_TEXT, CF_HDROP etc.

Please tell me how you would like to have it implemented.

Ciao, Mike
Avatar of esk

ASKER

Adjusted points to 300
Avatar of esk

ASKER

i want to be able to choose more than one line
(Multiselect) and press CTRL-C or popupmenu to choose copy , after that i want to select where i want to paste this line(s) thats all -- thanks. 300 points
Well, here's code to collect a string of all selected items and their subitems and send them to clipboard.

procedure TMainForm.CopyClick(Sender: TObject);

var
  Item: TListItem;
  Count: Integer;
  S: String;

begin
  with ListView1 do
    if SelCount > 0 then
    begin
      Item := Selected;
      Count := SelCount;
      S := '';
      while Count > 0 do
      begin
        S := S + Item.Caption + #9 + Item.SubItems.CommaText + #13;
        Dec(Count);
      end;
      Clipboard.SetTextBuf(PChar(S));
    end;
end;

If you simply want the lines (as you wrote at last) then this is all you need. Just paste the clipboard where ever you like.

Ciao, Mike
Well, here's code to collect a string of all selected items and their subitems and send them to clipboard.

procedure TMainForm.CopyClick(Sender: TObject);

var
  Item: TListItem;
  I, Count: Integer;
  S: String;

begin
  with ListView1 do
    if SelCount > 0 then
    begin
      Count := SelCount;
      S := '';
      I := 0;
      while (I < Items.Count) and (Count > 0) do
      begin
        Item := Items[I];
        if Item.Selected then
        begin
          S := S + Item.Caption + #9 + Item.SubItems.CommaText + #13;
          Dec(Count);
        end;
        Inc(I);
      end;
      Clipboard.SetTextBuf(PChar(S));
    end;
end;


If you simply want the lines (as you wrote at last) then this is all you need. Just paste the text from the clipboard whereever you like.

Ciao, Mike
Mmmh, I don't know why the first post went through, but you should ignore it as it doesn't advance in the items list.

Ciao, Mike
Avatar of esk

ASKER

what type "Clipboard" uses ? to assign, undeclare intentifier, can you give me paste code to?
Clipboard is a global object defined in the unit Clipbrd.pas. You need to add it to the uses clause of the form where the code is in.

For the paste code: How would you like to have the stuff pasted? Do want to paste it into the listview back (creating so new items) or would you like to have it in a memo or similar control which can hold text?

Ciao, Mike
Avatar of esk

ASKER

paste it into listview back, i choose lets say three
items and select copy and go anywhere in the listview and paste other three lines in ( anywhere i like )

i have three lines of text and want to make ten copyes quickly i choose copy , paste*10

Esk
ASKER CERTIFIED SOLUTION
Avatar of Lischke
Lischke

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of esk

ASKER

paste it into listview back, i choose lets say three
items and select copy and go anywhere in the listview and paste other three lines in ( anywhere i like )

i have three lines of text and want to make ten copyes quickly i choose copy , paste*10

Esk
Avatar of esk

ASKER

this work, but there are some bugs left.

i choose many items and do copy - paste some text came as &/&%/%$

i want to select where i want to paste the texts ( choose any item and the text will be addedd one down , not the bottom

Esk
Avatar of esk

ASKER

Adjusted points to 400
Avatar of esk

ASKER

Increase To 400
:-) DOn't do a refresh with the explorer refresh button or it will resend the last comment. Use the link in the upper right corner (Reload Question).

Ciao, Mike
Sorry fogot to adjust the code for insertion. Replace the line:

  Item := Items.Add;

with

  Item := Items.Insert(Selected.Index + 1);

This should do the job. For the bug: Is there a way you can surely reproduce it (exact steps)?

Ciao, Mike

Avatar of esk

ASKER

when i copy more than 4 lines the code always add "," this char. and more to.

can you fix this problem?

do you have to copy the data to clipboard?
can't you just copy the data to array?

Esk
Avatar of esk

ASKER

when i copy more than 4 lines the code always add "," this char. and more to.

can you fix this problem?

do you have to copy the data to clipboard?
can't you just copy the data to array?

Esk
Esk, sorry when I was to stupid to understand your true problem. I read copy and paste and automatically involved the clipboard. Of course you don't need the clipboard at all when you just want to copy items within the list view. Here's the code:

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  StdCtrls, ExtCtrls, ComCtrls;

type
  TForm1 = class(TForm)
    ListView1: TListView;
    procedure ListView1KeyDown(Sender: TObject; var Key: Word;
      Shift: TShiftState);
  private
    FCache: array of TListItem;
  end;

var
  Form1: TForm1;
 
implementation

{$R *.DFM}

procedure TForm1.ListView1KeyDown(Sender: TObject; var Key: Word;
  Shift: TShiftState);

var
  I,
  Count: Integer;
  Item: TListItem;

begin
  if Shift = [ssCtrl] then
  begin
    case Key of
      Ord('C'):
        with ListView1 do
          if SelCount > 0 then
          begin
            Count := SelCount;
            SetLength(FCache, Count);
            I := 0;
            while (I < Items.Count) and (Count > 0) do
            begin
              if Items[I].Selected then
              begin
                Dec(Count);
                FCache[Count] := Items[I];
              end;
              Inc(I);
            end;
          end;          
      Ord('V'):
        with ListView1 do
        begin
          for I := 0 to High(FCache) do
          begin
            if Assigned(Selected) then Item := Items.Insert(Selected.Index)
                                  else Item := Items.Add;
            Item.Assign(FCache[I]);
          end;
        end;
    end;
  end;
end;

end.

Ciao, Mike
Avatar of esk

ASKER

i have checked = true for all items, but if i have the checked = false, can you fix this?
Huh, what do you have now: checked = True or checked = False? In the case you want to tell me that the check state is not copied I can tell you it is! I just set TListView.CheckBoxes := True and copied a few items. Some of them are checked. After pasting them back all check states reflect the original state. So what is your problem?

Ciao, Mike
Avatar of esk

ASKER

Adjusted points to 500
Avatar of esk

ASKER

you are a genius, this all works

you get 500 points

Esk
Thank you very much :-) Raising the points while working on a problem significantly raises motivation.

Have a good day and

Ciao, Mike
Avatar of esk

ASKER

do you only get 50 points or 500?

Esk
I got 500 * 4 (for the A grading). After the answer has been accepted other can buy it for a tenth of its original value (here 50 points), if that's what you are wondering about.

Ciao, Mike
Avatar of esk

ASKER

i forgot one thing, how do i copy from listview1 and goto another listview in another form in same project and paste?

Many thanks

Esk
That is easy to do. Just replace:

with ListView1 do
         
with

with Sender as TListView do

Ciao, Mike
Avatar of esk

ASKER

i do that and doesn't working
Please esk, try harder before you ask again. The code *does* work as I described:

procedure TMainForm.ListView2KeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);

var
  I,
  Count: Integer;
  Item: TListItem;

begin
  if Shift = [ssCtrl] then
  begin
    case Key of
      Ord('C'):
        with Sender as TListView do
          if SelCount > 0 then
          begin
            Count := SelCount;
            SetLength(FCache, Count);
            I := 0;
            while (I < Items.Count) and (Count > 0) do
            begin
              if Items[I].Selected then
              begin
                Dec(Count);
                FCache[Count] := Items[I];
              end;
              Inc(I);
            end;
          end;
      Ord('V'):
        with Sender as TListView do
        begin
          for I := 0 to High(FCache) do
          begin
            if Assigned(Selected) then Item := Items.Insert(Selected.Index)
                                  else Item := Items.Add;
            Item.Assign(FCache[I]);
          end;
        end;
    end;
  end;
end;


Ciao, Mike
Avatar of esk

ASKER

sorry, i know this works if i have two listview on same form. But if i have
listview in another form and opens it and try to paste it doesn't work

Esk
Maybe you should be using the clipboard after all.
The cache is currently local to the form. If you want to have it accessible from other forms as well then make it a global variable.

Ciao, Mike
Avatar of esk

ASKER

Lischke, it doesn't work if i make global variable

Esk
Avatar of esk

ASKER

Do you have any solutions for me Lischke?
Mmmh, possibly. Can you tell me what exactly does not work. Or even better can you send me a small example program where this error occurs (public@lischke-online.de)?

Ciao, Mike
Avatar of esk

ASKER

Sending......

Esk
Okay I got it and despite the trouble we had here's another (and final) solution.

Create an action list and add two standard actions (via Ctrl + Ins or the menu): TEditCopy and TEditPaste. Insert this code in your first unit:

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  ComCtrls, StdCtrls, StdActns, ActnList;

type
  TForm1 = class(TForm)
    ListView1: TListView;
    Button1: TButton;
    ActionList1: TActionList;
    EditCopy1: TEditCopy;
    EditPaste1: TEditPaste;
    procedure Button1Click(Sender: TObject);
    procedure EditCopy1Execute(Sender: TObject);
    procedure EditPaste1Execute(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;
  ItemCache: array of TListItem;

procedure CopyToClipboard(Sender: TListView);
procedure PasteFromClipboard(Receiver: TListView);

implementation

uses Unit2;

{$R *.DFM}

procedure CopyToClipboard(Sender: TListView);

var
  I,
  Count: Integer;

begin
  with Sender do
    if SelCount > 0 then
    begin
      Count := SelCount;
      SetLength(ItemCache, Count);
      I := 0;
      while (I < Items.Count) and (Count > 0) do
      begin
        if Items[I].Selected then
        begin
          Dec(Count);
          ItemCache[Count] := Items[I];
        end;
        Inc(I);
      end;
    end;
end;

procedure PasteFromClipboard(Receiver: TListView);

var
  I: Integer;
  Item: TListItem;

begin
  with Receiver do
  begin
    for I := 0 to High(ItemCache) do
    begin
      if Assigned(Selected) then Item := Items.Insert(Selected.Index)
                            else Item := Items.Add;
      Item.Assign(ItemCache[I]);
    end;
  end;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  Form2.Show;
end;

procedure TForm1.EditCopy1Execute(Sender: TObject);

begin
  if ActiveControl is TListView then CopyToClipboard(ActiveControl as TListView)
                                else Beep;
end;

procedure TForm1.EditPaste1Execute(Sender: TObject);

begin
  if ActiveControl is TListView then PasteFromClipboard(ActiveControl as TListView)
                                else Beep;
end;

end.


Note: Although the procedures are named with ...Clipboard they don't use the clipboard in reality. It's just how one would name them if they would...

In your second (and every other) form you have to insert the same actions and assign the same calls in the execute handlers which refer then to the methods stored in form1:

unit Unit2;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  ComCtrls, StdActns, ActnList;

type
  TForm2 = class(TForm)
    ListView1: TListView;
    ActionList1: TActionList;
    EditCopy1: TEditCopy;
    EditPaste1: TEditPaste;
    procedure EditCopy1Execute(Sender: TObject);
    procedure EditPaste1Execute(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form2: TForm2;

implementation

uses Unit1;

{$R *.DFM}

procedure TForm2.EditCopy1Execute(Sender: TObject);
begin
  if ActiveControl is TListView then CopyToClipboard(ActiveControl as TListView)
                                else Beep;
end;

procedure TForm2.EditPaste1Execute(Sender: TObject);
begin
  if ActiveControl is TListView then PasteFromClipboard(ActiveControl as TListView)
                                else Beep;
end;

end.

Cioa, Mike
Avatar of esk

ASKER

uff, thank you very much "Lischke", this works very well but one thing

if i do copy and try paste into another listview, then item will will "rewerse"

Maybe you can fix this later?

Thanks
Esk
you probably can just change the order of the paste

change the line:
for I := 0 to High(ItemCache) do

to:
for I := High(ItemCache) downto 0 do ..

something like that should do it in right order..
Avatar of esk

ASKER

yes!!!

this works. Thanks Barry.