[Webinar] Streamline your web hosting managementRegister Today

x
  • Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 1291
  • Last Modified:

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
0
esk
Asked:
esk
  • 23
  • 17
  • 3
  • +2
1 Solution
 
rwilson032697Commented:
Listening
0
 
intheCommented:
also listening..
0
 
rwilson032697Commented:
Go to bed Barry!!!! :-)
0
Take Control of Web Hosting For Your Clients

As a web developer or IT admin, successfully managing multiple client accounts can be challenging. In this webinar we will look at the tools provided by Media Temple and Plesk to make managing your clients’ hosting easier.

 
intheCommented:
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...
0
 
philipleighsCommented:
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.
0
 
eskAuthor Commented:
example? philipleighs
0
 
LischkeCommented:
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
0
 
eskAuthor Commented:
Adjusted points to 300
0
 
eskAuthor Commented:
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
0
 
LischkeCommented:
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
0
 
LischkeCommented:
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
0
 
LischkeCommented:
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
0
 
eskAuthor Commented:
what type "Clipboard" uses ? to assign, undeclare intentifier, can you give me paste code to?
0
 
LischkeCommented:
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
0
 
eskAuthor Commented:
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
0
 
LischkeCommented:
Okay Esk, here is the code. I hope it contains all you need. Use it in the OnKeyDown event of your listview:

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

var
  Item: TListItem;
  I,
  Count,
  TabPos: Integer;
  S, Line: String;
  Head,
  Tail: PChar;

begin
  if Shift = [ssCtrl] then
  begin
    case Key of
      Ord('C'):
        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.AsText := S;
          end;        
      Ord('V'):
        with ListView1 do
        begin
          // get the text from clipboard if there's any
          if Clipboard.HasFormat(CF_TEXT) then
          begin
            // split the text into lines
            Head := PChar(Clipboard.AsText);
            while Head^ <> # do
            begin
              Tail := Head;
              while not (Tail^ in [#0, #13]) do Inc(Tail);
              SetString(Line, Head, Tail - Head);
              if Line <> '' then
              begin
                // find tab position as this is our indication for the main entry
                TabPos := Pos(#9, Line);
                Item := Items.Add;
                // no tabulator means that the text came from somewhere but not from this list view
                if TabPos = 0 then Item.Caption := Line
                              else
                begin
                  // strip main caption and assign subitems
                  Item.Caption := Copy(Line, 1, TabPos - 1);
                  Delete(Line, 1, TabPos);
                  Item.SubItems.CommaText := Line;
                end;
              end;
              Head := Tail;
              if Head^ <> #0 then
              begin
                Inc(Head);
                // skip an eventual line feed
                if (Tail^ = #13) and (Head^ = #10) then Inc(Head);
              end;
            end;
          end;
        end;
    end;
  end;
end;


Ciao, Mike
0
 
eskAuthor Commented:
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
0
 
eskAuthor Commented:
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
0
 
eskAuthor Commented:
Adjusted points to 400
0
 
eskAuthor Commented:
Increase To 400
0
 
LischkeCommented:
:-) 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
0
 
LischkeCommented:
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

0
 
eskAuthor Commented:
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
0
 
eskAuthor Commented:
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
0
 
LischkeCommented:
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
0
 
eskAuthor Commented:
i have checked = true for all items, but if i have the checked = false, can you fix this?
0
 
LischkeCommented:
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
0
 
eskAuthor Commented:
Adjusted points to 500
0
 
eskAuthor Commented:
you are a genius, this all works

you get 500 points

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

Have a good day and

Ciao, Mike
0
 
eskAuthor Commented:
do you only get 50 points or 500?

Esk
0
 
LischkeCommented:
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
0
 
eskAuthor Commented:
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
0
 
LischkeCommented:
That is easy to do. Just replace:

with ListView1 do
         
with

with Sender as TListView do

Ciao, Mike
0
 
eskAuthor Commented:
i do that and doesn't working
0
 
LischkeCommented:
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
0
 
eskAuthor Commented:
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
0
 
philipleighsCommented:
Maybe you should be using the clipboard after all.
0
 
LischkeCommented:
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
0
 
eskAuthor Commented:
Lischke, it doesn't work if i make global variable

Esk
0
 
eskAuthor Commented:
Do you have any solutions for me Lischke?
0
 
LischkeCommented:
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
0
 
eskAuthor Commented:
Sending......

Esk
0
 
LischkeCommented:
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
0
 
eskAuthor Commented:
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
0
 
intheCommented:
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..
0
 
eskAuthor Commented:
yes!!!

this works. Thanks Barry.
0

Featured Post

Free Tool: SSL Checker

Scans your site and returns information about your SSL implementation and certificate. Helpful for debugging and validating your SSL configuration.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

  • 23
  • 17
  • 3
  • +2
Tackle projects and never again get stuck behind a technical roadblock.
Join Now