Memo1, Memo2 & Edit1 Add Additional Lines

Hello All;

Lets see if I can explain this so that everyone can understand it.

Edit1.Text := 'New';
Memo1.Lines -----
Memo2.Lines -----

OK.
  I need to have it to where when you type in a "Line" into [Memo1]
It will Trigger [Edit1] to insert a new line into [Memo2]

So it will do something like this:
Edit1.Text := 'New',

Memo1.Text                    Memo2
Something                       New
Everything                        New
Possibly                           New

===============
So, as you can see.
The information from the TEdit is being Repeatedly inserted into the Memo2.
Every time that Memo1 creates a [Break] (Press Enter Key to Tab Down)

Any idea's on this one?

Thanks All;
Carrzkiss
LVL 31
Wayne BarronAuthor, Web DeveloperAsked:
Who is Participating?
 
2266180Connect With a Mentor Commented:
giid practice sais not to make ugly hacks, so I'm not going to. But instead, I will add another event to it that gets fired on paste:

unit Unit1;

interface

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

type
  TPasteEvent = procedure(Sender:TObject; pastedString:string) of object;
  TMemo = class(StdCtrls.TMemo)
  private
    FOnNewLine:TNotifyEvent;
    FOnPaste:TPasteEvent;
    procedure mypaste(var msg:TMessage); message WM_Paste;
  public
    property OnNewLine:TNotifyEvent read FOnNewLine write FOnNewLine;
    property OnPaste:TPasteEvent read FOnPaste write FOnPaste;
  end;

  TForm1 = class(TForm)
    Memo1: TMemo;
    Memo2: TMemo;
    Edit1: TEdit;
    procedure Memo1KeyPress(Sender: TObject; var Key: Char);
    procedure FormCreate(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
    procedure FormOnNewLine(Sender: TObject);
    procedure FormOnPaste(Sender: TObject; pasteString:String);
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.Memo1KeyPress(Sender: TObject; var Key: Char);
begin
  if key=#13 then
    memo2.lines.add(edit1.text);
end;

procedure TMemo.mypaste(var msg: TMessage);
var
  Handle: THandle;
  CText: string;
  LText: string;
  AText: string;
  i:integer;
begin
  if IsClipboardFormatAvailable(CF_TEXT) then
  begin
    try
      OpenClipBoard(Self.Handle);
      Handle := GetClipboardData(CF_TEXT);
      if Handle = 0 then
        Exit;
      CText := StrPas(GlobalLock(Handle));
      GlobalUnlock(Handle);
      if assigned(FOnNewLine) then
      begin
        i:=1;
        while i<=length(ctext) do
        begin
          if (ctext[i]=#10) and (ctext[i-1]=#13) then// crlf
            FOnNewLine(self);
          inc(i);
        end;
      end;
      if assigned(FOnPaste) then
        FOnPaste(self, CText);
      LText := '';
      if SelStart > 0 then
        LText := Copy(Text, 1, SelStart);
      LText := LText + CText;
      AText := '';
      if (SelStart + 1) < Length(Text) then
        AText := Copy(Text, SelStart + SelLength + 1, Length(Text) - SelStart + SelLength + 1);
      Text := LText + AText;
    finally
      CloseClipBoard;
    end;
  end;{}
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  memo1.OnNewLine:=FormOnNewLine;
  memo1.OnPaste:=FormOnPaste;
end;

procedure TForm1.FormOnNewLine(Sender: TObject);
begin
  memo2.lines.add(edit1.text);
end;

procedure TForm1.FormOnPaste(Sender: TObject; pasteString: String);
begin
  if copy(pasteString,length(pasteString)-1,2)<>#13#10 then// only do this if no line break at the end
    memo2.lines.add(edit1.text);
end;

end.
0
 
2266180Commented:
pretty simple actually :)

put 2 memos, 1 editbox on the form of a new application. assign an event to the onkeypress of memo1 and then replace all code from unti 1 with:
unit Unit1;

interface

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

type
  TForm1 = class(TForm)
    Memo1: TMemo;
    Memo2: TMemo;
    Edit1: TEdit;
    procedure Memo1KeyPress(Sender: TObject; var Key: Char);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.Memo1KeyPress(Sender: TObject; var Key: Char);
begin
  if key=#13 then
    memo2.lines.add(edit1.text);
end;

end.

and you're done. you can of course customize the
    memo2.lines.add(edit1.text);
with something like:
    memo2.text:=memo2.text+' '+edit1.text+#13#10;

0
 
Wayne BarronAuthor, Web DeveloperAuthor Commented:
It works good except but when you "Paste" something into the Memo1.
Once you paste into Memo1, the Event is only fired "1-Time" Thus only putting
The Text for the Edit1, in at the very first line.
So if you [Paste] 50-Lines. Only the 1st Line gets information from Edit1.Text

Any idea's on how to make it work on [Memo1.PasteFromClipboard] ?

Thanks a bunch
0
Upgrade your Question Security!

Your question, your audience. Choose who sees your identity—and your question—with question security.

 
Wayne BarronAuthor, Web DeveloperAuthor Commented:
Ciuly

If this is going to be a Difficult one, then once you have a working code.
Or if anyone has a working code that will work with the [Memo1.PasteFromClipboard]
I will gladly pop the Points up to: 500

Thanks All;
0
 
atul_parmarCommented:
The good solution is to manage the paste yourself. Here is how you can do it.
derive a class from TMemo and add a message handler for WM_PASTE

  TMyMemo = class(TMemo)
    procedure OnPaste(var Msg : TMessage); message WM_PASTE;
  end;

implement it as

procedure TMyMemo.OnPaste(var Msg: TMessage);
var
  s : TStringList;
  i : integer;
begin
  if Clipboard.HasFormat(CF_TEXT) then
  begin
    s := TStringList.Create;
    s.Text := Clipboard.AsText;
    for i:= 0 to s.Count - 1 do
      Form1.Memo2.Lines.Add(Form1.Edit1.Text);
    s.Free;
  end;
  inherited;
end;

I hope this will help you to overcome the paste problem. :)

Atul
0
 
2266180Commented:
here is the uupdated code:

unit Unit1;

interface

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

type
  TMemo = class(StdCtrls.TMemo)
  private
    FOnNewLine:TNotifyEvent;
    procedure mypaste(var msg:TMessage); message WM_Paste;
  public
    property OnNewLine:TNotifyEvent read FOnNewLine write FOnNewLine;
  end;

  TForm1 = class(TForm)
    Memo1: TMemo;
    Memo2: TMemo;
    Edit1: TEdit;
    procedure Memo1KeyPress(Sender: TObject; var Key: Char);
    procedure FormCreate(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
    procedure FormOnNewLine(Sender: TObject);
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.Memo1KeyPress(Sender: TObject; var Key: Char);
begin
  if key=#13 then
    memo2.lines.add(edit1.text);
end;

procedure TMemo.mypaste(var msg: TMessage);
var
  Handle: THandle;
  CText: string;
  LText: string;
  AText: string;
  i:integer;
begin
  if IsClipboardFormatAvailable(CF_TEXT) then
  begin
    try
      OpenClipBoard(Self.Handle);
      Handle := GetClipboardData(CF_TEXT);
      if Handle = 0 then
        Exit;
      CText := StrPas(GlobalLock(Handle));
      if assigned(FOnNewLine) then
      begin
        i:=1;
        while i<=length(ctext) do
        begin
          if (ctext[i]=#10) and (ctext[i-1]=#13) then// crlf
            FOnNewLine(self);
          inc(i);
        end;
      end;
      GlobalUnlock(Handle);
      LText := '';
      if SelStart > 0 then
        LText := Copy(Text, 1, SelStart);
      LText := LText + CText;
      AText := '';
      if (SelStart + 1) < Length(Text) then
        AText := Copy(Text, SelStart + SelLength + 1, Length(Text) - SelStart + SelLength + 1);
      Text := LText + AText;
    finally
      CloseClipBoard;
    end;
  end;{}
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  memo1.OnNewLine:=FormOnNewLine;
end;

procedure TForm1.FormOnNewLine(Sender: TObject);
begin
  memo2.lines.add(edit1.text);
end;

end.

the reason for defining the TMemo like that is that it will be used instead of the one from stdctrl (you are adding some stuff to it/extending it). this has it's advantages: you don't need to modify any code. just put that TMemo I defined in a unit if you want it to be used in more projects or more units and MAKE SURE that that unit with my TMemo is AFTER the StdCtrls in the uses clause.
thats it :)
0
 
atul_parmarCommented:
ciuly, I think if you want it to work without modifying any line of code then just changing the TMyMemo to TMemo is enough. As it is short and simple. :)

However, using the same class name is BAD practice. Instead creating a custom memo component (with different name) is ideal solution.
0
 
2266180Commented:
I will have to disagree with you atul:
1) if you want to access a protected property/function, you will need my method (there ere a few cases here on EE and in my own experience) It's not the same name, it's overwriting the old one. a sensitive difference in terms  :) Plus that you will have to modify the code to use tmymemo instead of tmemo: the designer might not cope with that (see dfm). too much manual stuff to do ;)
2) your code hardcoded the memo2 into it. what if I want to have 3 or 4 memo's getting the same or different result? I gave a general solution and it's up to the programmer on how to use it.
what if you want that one memo receives an add edit1.text on all new lines, and another receives them only on odd ones? the list can continue ;)
0
 
atul_parmarConnect With a Mentor Commented:
Perhaps you didn't get me. Here is what I mean. As continuing with my previous code comment.

TMemo = class(StdCtrls.TMemo)
    procedure OnPaste(var Msg : TMessage); message WM_PASTE;
  end;

implement it as

procedure TMemo.OnPaste(var Msg: TMessage);
var
  s : TStringList;
  i : integer;
begin
  if Clipboard.HasFormat(CF_TEXT) then
  begin
    s := TStringList.Create;
    s.Text := Clipboard.AsText;
    for i:= 0 to s.Count - 1 do
      Form1.Memo2.Lines.Add(Form1.Edit1.Text);
    s.Free;
  end;
  inherited;
end;

1. As long as the access protected property/function is concerned, in Delphi scope of protected member is upto unit level NOT class level.

2. I tested it and it works fine on D7. and it does not require to modify any existing line of code :)

Atul.
0
 
2266180Commented:
2) true. that indeed I didn not understand correrctly. but you still have the hardcoded stuff in it :)
1) true, but in case of TMemo and otehr components that come with delphi, you don't write your code in those units and recompile the bpl's and everything, do you? the method is to be used in cases where extra functionality needs to be added to existing components to which you cannot modify the unit files or recompile the component in an easy manner (I'm not saying it's impossible to recompile delphi's "own" compnents, it's just not trivial)
0
 
atul_parmarCommented:
Anyway, this is just for knowledge sharing. :)
0
 
2266180Commented:
true. I myself learned a lot here, even though my main "activity" is helping others :D
and my job is not even delphi related.
0
 
Wayne BarronAuthor, Web DeveloperAuthor Commented:
[ciuly];

Good Morning.
I tried your solution and it does not work?
I paste to the Memo1 and the Memo2 does nothing.
I hit the [Enter] key, and it add's in [1] entry into the Memo2
And I need it to add in the Same amount of lines that Memo1 has.

Going off to try [atul_parmar] code now.
0
 
2266180Commented:
weird. it works fine for me. are you sure you have copy/pasted the entire thing without changing anything?
0
 
Wayne BarronAuthor, Web DeveloperAuthor Commented:
Sorry.
Forgot to Trigger the [OnCreate]
I had Triggered the [OnKeyPress] for the Memo1
But not the OnCreate, when I pasted the code.

So far so good! :)

I tested the code from [atul_parmar]
And cannot get it to compile.

Something about
Undeclaired Identifier on: Clipboard
 if Clipboard.HasFormat(CF_TEXT) then   // <--

I am going to run the code from you [ciuly]
And make sure that it can withstand what I am about to do with it.
And make sure that I can get it to work in my actual project.
And I will come in within the hour to inform.

Thank you
0
 
2266180Commented:
you must
uses clipbrd;
for atul's code to compile ;)
0
 
atul_parmarCommented:
Yop will have to put the Clipbrd unit in your uses list.
0
 
Wayne BarronAuthor, Web DeveloperAuthor Commented:
Yep, just realized that. (Just woke up a few minutes ago, it is 8:55am here)

In your code Ciuly.
Need one more thing to make it work.

The Very last line is not getting the TEdit to the TMemo2 from the TMemo1.
Basically like this:

Edit1.Text := 'One';

Memo1                    Memo2
Are                          One
Are                          One
Are                          

In the above example, you see that "Memo1" has "3" Lines during the [Paste]
And the "Memo2" only has 2 lines during the paste.
This would be because there is not an extra "LineBreak" after the Last Line pasted in.

A #13 (or) #10
Would break it, but were to put it at?
0
 
Wayne BarronAuthor, Web DeveloperAuthor Commented:
atul_parmar
The same thing applies to your code as well.
(Read the last information sent to: Ciuly)
0
 
atul_parmarCommented:
It's not big thing just remove the -1 e.g.

procedure TMemo.OnPaste(var Msg: TMessage);
var
  s : TStringList;
  i : integer;
begin
  if Clipboard.HasFormat(CF_TEXT) then
  begin
    s := TStringList.Create;
    s.Text := Clipboard.AsText;
    for i:= 0 to s.Count do
      Form1.Memo2.Lines.Add(Form1.Edit1.Text);
    s.Free;
  end;
  inherited;
end;
0
 
atul_parmarCommented:
one more thing I would like to suggest you (if you use ciuly's code) is to replace the
     CText := StrPas(GlobalLock(Handle));
      if assigned(FOnNewLine) then
      begin
        i:=1;
        while i<=length(ctext) do
        begin
          if (ctext[i]=#10) and (ctext[i-1]=#13) then// crlf
            FOnNewLine(self);
          inc(i);
        end;
      end;
      GlobalUnlock(Handle);
part with using TStringlist. Because going through each character and checking for CRLF will take much time when you paste BIG sized code.
0
 
2266180Commented:
atul, I think you should look in the classes.pas file from delphi and you will see that the algorithm used for setting the Text property is much more complicated and takes a little more time, not mentioning the time that takes for creating the stringlist class and freeing it. that searching algorithm is pretty optimized for it's puurpose ;) (maybe the length(ctext) can be replaced with a variable, but otehr than that I don't see any speed/memory improvements :)
0
 
Wayne BarronAuthor, Web DeveloperAuthor Commented:
Sorry [atul_parmar] Your code did produce the correct # of lines.
The ScrollBars were not equal, so I do appologize.


Ciuly.
Code works great.

I am going to Up the points to 500.

Ciuly - Accepted
Atul_parmar - Assisted.

I think you both for the information, and the time.
And the knowledge and know-how, from reading your comments.
That is what makes EE such a cool place to be a part of.
Everyone how their own opinion for how they like to do things.
Sometimes the opinion's of others can be a little too far fetched, while
At other times, the Opinion from a fellow EE can really make a world of difference.

Both of you come across with some great code, tips and what "you" as a programmer
Think should be done, and should not be done.
Both are equally correct in your own right, as I will not judge on who is correct or not.
You both gave 110% to this Post, and did not stop with it.
Both equally as fast on response time and comments posted.

Well, that is not on the Rambling from me.

Ciuly & Atul;
I wish you both the best, and I think ou both very much for the information that we all received here today.

Wayne
0
 
atul_parmarCommented:
cuily, your argument seems right.
what abt holding the count property before paste and then use it after paste.

e.g.
  cnt := self.count; // count of lines before paste
  // here your paste operation
  for i:= cnt to self.count do
     FOnNewLine(self);
0
 
Wayne BarronAuthor, Web DeveloperAuthor Commented:
I will let you both decide on what to do, and what not to do.
As I am still learning the code provided.
Once a solid sollution/understanding between the both of you is accomplished
I will add in (or) remove code from my Project.

Thanks Guys.
Wayne
0
 
2266180Commented:
that is indeed a neat idea:

something like this should work (not tested)

procedure TMemo.OnPaste(var Msg: TMessage);
var
  i,cnt : integer;
begin
  cnt := count; // count of lines before paste
  inherited;
  for i:= cnt to count do
    if assigned(FOnNewLine)
      FOnNewLine(self);
end;

@carrzkiss: thank you for your appreciation :)
0
 
2266180Commented:
this is tested and works:

procedure TMemo.OnPaste(var Msg: TMessage);
var
  i,cnt : integer;
begin
  cnt := lines.count; // count of lines before paste
  inherited;
  for i:= cnt to lines.count do
    if assigned(FOnNewLine) then
      FOnNewLine(self);
end;
0
 
atul_parmarCommented:
Great! now it looks complete. :)
0
 
Wayne BarronAuthor, Web DeveloperAuthor Commented:
Ciuly
Is the:           TMemo.OnPaste
To Replace    TMemo.MyPaste
(or)
Is this it's own Procedure to be added in?
0
 
2266180Commented:
to be replaced. me and atul used different names for the same procedure(event) ;)
0
 
2266180Commented:
sorry. incorrect. just to make sure I don't generate otehr confusion:

procedure TMemo.MyPaste(var Msg: TMessage);
var
  i,cnt : integer;
begin
  cnt := lines.count; // count of lines before paste
  inherited;
  for i:= cnt to lines.count do
    if assigned(FOnNewLine) then
      FOnNewLine(self);
end;

there :) (repalce only the body of the function ;) )
0
 
Wayne BarronAuthor, Web DeveloperAuthor Commented:
That is what I did. :)
Thanks "Ciuly"

You both have a great day.
Wayne
0
 
Wayne BarronAuthor, Web DeveloperAuthor Commented:
Update on the "Updated" Code.

procedure TMemo.MyPaste(var Msg: TMessage);
var
  i,cnt : integer;
begin
  cnt := lines.count; // count of lines before paste
  inherited;
  for i:= cnt to lines.count do
    if assigned(FOnNewLine) then
      FOnNewLine(self);
end;

The code is very buggy.
After a few times of using it, it stops responding.
Replacing it with the Original Code, work perfectly.

So, rather it is a good idea to have the above code, it is not ready yet.

Too recreate the issue.
========================================
Have the above code in place.
Work in Delphi, then [Run] the project.
Do this several times, and you will see that it stops working.
========================================
Wayne
0
 
2266180Commented:
Hi Wayne,

I'm a little caught up in a project right now.
that is pretty weird. I'll look into it tomorrow if atul doesn't do it before me :)
0
 
Wayne BarronAuthor, Web DeveloperAuthor Commented:
OK.
It is not a big problem right now.
As the code that you originally posted is working great for now.
But will wait your outcome.

Take Care Now;
Wayne
0
 
atul_parmarCommented:
That's ok Wayne.
0
 
2266180Commented:
hm... I tried to reproduce but I couldn't. However, I found and fixed a bug :) (when you select and copy say x lines, then you again select x lines and paste, it add a new entry in memo2, even though no line has been added to memo1)
updated code:

unit Unit1;

interface

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

type
  TPasteEvent = procedure(Sender:TObject; pastedString:string) of object;
  TMemo = class(StdCtrls.TMemo)
  private
    FOnNewLine:TNotifyEvent;
    procedure mypaste(var msg:TMessage); message WM_Paste;
  public
    property OnNewLine:TNotifyEvent read FOnNewLine write FOnNewLine;
  end;

  TForm1 = class(TForm)
    Memo1: TMemo;
    Memo2: TMemo;
    Edit1: TEdit;
    procedure Memo1KeyPress(Sender: TObject; var Key: Char);
    procedure FormCreate(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
    procedure FormOnNewLine(Sender: TObject);
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.Memo1KeyPress(Sender: TObject; var Key: Char);
begin
  if key=#13 then
    memo2.lines.add(edit1.text);
end;

procedure TMemo.mypaste(var msg: TMessage);
var
  i,cnt : integer;
begin
  cnt := lines.count; // count of lines before paste
  inherited;
  if cnt<>lines.count then
    for i:= cnt to lines.count-1 do
      if assigned(FOnNewLine) then
        FOnNewLine(self);
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  memo1.OnNewLine:=FormOnNewLine;
end;

procedure TForm1.FormOnNewLine(Sender: TObject);
begin
  memo2.lines.add(edit1.text);
end;

end.

I would need a ste-by-step reproduction, that works every time. if you can provide that :)
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

All Courses

From novice to tech pro — start learning today.