Solved

Limit the number of lines in a Memo

Posted on 2004-04-13
22
1,257 Views
Last Modified: 2010-04-05
I need to limit the max number of lines a person can type into a memo control which includes continuous typing or blank lines (ie pressing the enter button without typing anything on that line.)  

Here are some example of what I am looking for.

Normal Example (Max line count of 5)

line 1 text (press enter button for new line)
line 2 text (press enter button for new line)
line 3 text (press enter button for new line)
line 4 text (press enter button for new line)
line 5 text (press enter button for new line but nothing happens)

continuous Typing Example (Max line count of 5)

line 1 text (press enter button for new line)
line 2 text (press enter button for new line)
line 3 text (press enter button for new line)
line 4 text (press enter button for new line)
line 5 text (user keeps typing but at the end of the line it stops typing)

Blank Lines Example (Max line count of 5)

line 1 (user does not type anything but just presses enter)
line 2 (user does not type anything but just presses enter)
line 3 (user does not type anything but just presses enter)
line 4 (user does not type anything but just presses enter)
line 5 (user does not type anything but just presses enter but nothing happens)

Anyway that is about it and just so you know I have tried various methods I found on the net and none of them worked properly or had undesireable side effects and here is a list of links that I tried.

http://www.elists.org/pipermail/delphi/2001-February/013321.html (causes the memo to flash when the limit is reached .... not very pretty i must say)

http://www.swissdelphicenter.ch/en/showcode.php?id=964 (failed the continuous typing example and slows down the entire program when the max line limit has been reached)

http://free.cjb.hu/d/e/delphicikk/listaz.php?id=1363 (failed the continuous typing example)

http://free.cjb.hu/d/e/delphicikk/listaz.php?id=1979 (causes an access violation error for the blank line example - would have been fine otherwise so if you can change this one so it does not cause the error then that will work to)
0
Comment
Question by:voodoo22
  • 10
  • 7
  • 4
  • +1
22 Comments
 
LVL 12

Expert Comment

by:Ivanov_G
Comment Utility
procedure TForm1.Memo1KeyPress(Sender: TObject; var Key: Char);
begin
  if Memo1.Lines.Count = 5 then
    begin
      Key := #0;
      Exit;
    end;
end;
0
 
LVL 12

Assisted Solution

by:Ivanov_G
Ivanov_G earned 50 total points
Comment Utility

    I have better dicision now :

procedure TForm1.Memo1KeyPress(Sender: TObject; var Key: Char);
var
  MAX_LINES              : Integer;
  LINE_LENGTH            : Integer;
begin
  MAX_LINES         := 5;
  LINE_LENGTH       := 255;
  if (Memo1.Lines.Count = MAX_LINES) then
    if (Key = #13) or (length(Memo1.Lines[MAX_LINES-1]) > LINE_LENGTH ) then
      begin
        Key := #0;
        Exit;
      end;
  if (Memo1.Lines.Count > MAX_LINES) and (Key = #13) then
    begin
      Key := #0;
      Exit;
    end;
end;
0
 

Author Comment

by:voodoo22
Comment Utility
Hello Ivanov G

Thx for the code but it fails the "continuous typing" test

Example... (actual resuls form a memo with your code)

line 1
line 2
line 3
line 4
line5 nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee

and I could have kept on typing if i wanted to and what it should do is once the text reaches the end of line5 it should not allow any more characters to be typed.
0
 
LVL 2

Expert Comment

by:xxflip
Comment Utility
I would set the MAXLENGTH property and make a routine to block the enter key on the ONKEYPRESS event so that no more than 5 lines were entered, like the first one Ivanov_G suggested

But remember that only the MAXLENGTH will be respected on a PASTE
0
 
LVL 12

Expert Comment

by:Ivanov_G
Comment Utility

   voodoo22, change to LINE_LENGTH to 4096 for example. this is just a quick idea ...

   use OnChange event and monito she ShitfState and V char (paste)
0
 

Author Comment

by:voodoo22
Comment Utility
xx flip and Ivanov_G .... the only part of what either of you said that I understood was what Ivanov_G said about changinging Line_Length to 4096 which did nothing btw.
0
 

Author Comment

by:voodoo22
Comment Utility
additionally as I stated in my original post if anyone can fix the code on this page http://free.cjb.hu/d/e/delphicikk/listaz.php?id=1979 so it will not cause a Illegal Operation error when hitting the enter button a bunch of time then that will work as well.
0
 

Author Comment

by:voodoo22
Comment Utility
xxflip,

I reread your comment and setting the MaxLength property would not make a difference because the person could simply type something like this.

MaxLength set to 500 for example and 5 line limit.

1
2
3
4
5nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn upto 500 characters

which would wordwrap to a new line after about 100 chracters or so and turning off wordwrap will not work either for my purposes
0
 
LVL 12

Expert Comment

by:Ivanov_G
Comment Utility

  MAX_LINES      - the number of lines - it my example 5 lines
  LINE_LENGTH   - how many characters per line...
0
 
LVL 2

Assisted Solution

by:xxflip
xxflip earned 50 total points
Comment Utility
Try this


...
Const
  LimitChars = 10;
...
  public
    { Public declarations }
    CurrLine:Integer;
...

procedure TForm1.Memo1KeyPress(Sender: TObject; var Key: Char);
begin
  if Key <> #8 then begin //Allow backspace
    If (Memo1.Lines.Count = 5)and(Key = #13) then Key:=#0; //don't allow mor than 5 lines
    if (Length(Memo1.Lines[CurrLine]) >= LimitChars)and(Key <> #13) then Key:=#0; //don't allow lines longer than LimitChars chars
  end;
end;

procedure TForm1.Memo1KeyUp(Sender: TObject; var Key: Word;
  Shift: TShiftState);
begin
  CurrLine:=Memo1.CaretPos.Y;
end;
0
 

Author Comment

by:voodoo22
Comment Utility
Hello Again ... I am sorry to say that both of the methods you have posted fail the "continuous typing test"

(Ivanov_G) With a new memo and your code type the following and you will see what I mean.

Type 1 (press enter)
Type 2 (press enter)
Type 3 (press enter)
Type 4 (press enter)
Type 5 (then hold down the "N" key and watch it as it goes on forever and ever ... ignoring the LINE_LENGTH stuff)

(xxflip) set the number for the LimitChars Const to something like 100 and watch and start typing and you will see that not only does it go well beyond the Limit it also allows you to press the enter key and make new lines even if Max Lines is set to 5.

Something I have noticed in both examples is that if I set the character limit to a value that does not wrap the line then the code works but as I have said before limiting the amount of characters per line is not really an option anyway for this reason....

Example.... Setting Line Limit to 5 and Character Limit to 25.

this is line one text see
.........................
ZZZZZZZZZZZZZZZZZZZZZZZZZ
()()()()()()()()()()()()(
&&&&&&&&&&&&&&&&&&&&&&&&&

Each of the lines above contains 25 characters but because all characters are not the same width it makes the lines shorter or longer depending on the characters typed which makes the text look ugly and confuses the end user... that is why using character per line limits is not an option.
0
Find Ransomware Secrets With All-Source Analysis

Ransomware has become a major concern for organizations; its prevalence has grown due to past successes achieved by threat actors. While each ransomware variant is different, we’ve seen some common tactics and trends used among the authors of the malware.

 
LVL 2

Expert Comment

by:xxflip
Comment Utility
well I have tested my code and it seems to work fine (with wordwrap turned off).
As to the way it looks, just chose COURIER NEW as the memo font and you wont have a problem.
0
 

Author Comment

by:voodoo22
Comment Utility
xxflip thats not an option either as there is no way to guarantee that everyone that uses the program has that font installed.
0
 
LVL 2

Expert Comment

by:xxflip
Comment Utility
of course it is, that is a native windows font so unless they have been messing around with the system fonts (in which case they know what to do) they will have it.
0
 

Author Comment

by:voodoo22
Comment Utility
having wordwrap turned off is not an option then because to be honest it does not wrap the lines which is what memos are for.
0
 

Author Comment

by:voodoo22
Comment Utility
This is the code from the last link I posted above and if anyone can tell me why removing the
(Ord(s[i]) = 10)  stuff from the code seems to get rid of the "Illegal Operation Error" and more importanly what effect does removing it have ?

procedure TForm1.Memo1Change(Sender: TObject);
var
  i: Integer;
  s: string;
begin
  i := Length(Memo1.Lines.Text);
  {Limit the number of lines to 3}
  if Memo1.Lines.Count > 3 then
  begin
    s := Memo1.Lines.Text;
    Delete(s, i, 1);
    {Remove line wrap}
    i := Length(s);
    while (Ord(s[i]) = 10) or (Ord(s[i]) = 13) do
    begin
      Delete(s, i, 1);
      i := Length(s);
    end;
    Memo1.Lines.Text := s;
    {posistion cursor at end of memo}
    Memo1.SelStart := Length(s);
    Memo1.SelLength := 0;
    ShowMessage('Over Max Lines');
  end;
end;
0
 
LVL 2

Expert Comment

by:xxflip
Comment Utility
I tested the previous code and I get no error, it also doesn't work the way you need it to work.

The best solution is probably to set either a MAXLENGTH or a line limit.

Why do you need to limit this? Can you provide some more information on the project? Maybe there is another way to solve it!
0
 

Author Comment

by:voodoo22
Comment Utility
xxfilp ... did you try just pressing the enter button a few times on a blank memo while running the code I posted.. The code runs fine if you have something in the memo but (for me atleast) if the memo is blank and you just push the enter key then after max lines is reached it will give a Illegal Operation Error.

I am not sure about what part of it that does not work the way I need it to ... it stops the lines at the limit you set and it does not wrap the last line if you keep typing so other then the error it's exaclty what I need.

The reason I need to limit the lines is because once a person enters the text into the memo it is placed on a label which is autosized on the vertical plane and then that label is displayed on the screen and if a person types 100 lines in the memo and presses the button the lable will be to large for the user to see all of the text on the screen. I realize I could show the text in a differnt way (using a control with scrollbars or something like that) but again that is not an option as it would defeat the entire purpose of my program in the first place.
0
 
LVL 2

Expert Comment

by:xxflip
Comment Utility
your code gives no error on my computer, but it doesn't limit anything.

My example does all but wrap the text at the end of the line.

Why not limit the maxlength of the memo, and then have the label resized to the max size allowed (autosize = false) and the WORDWRAP, ALIGNMENT and LAYOUT properties to what suits you best. With a couple tests you can figure out what is the length limit for the label.
0
 
LVL 33

Accepted Solution

by:
Slick812 earned 125 total points
Comment Utility
hello voodoo22, you might try this code for the OnChange Event of  Memo1 a TMemo control with or without word wrap - - -


procedure TForm1.Memo1Change(Sender: TObject);
const
MaxLines = 5;

var
  s: String;
  i: Integer;
  pGet: PChar;

begin
if ((Memo1.Lines.Count = MaxLines) and
   (Memo1.Lines.Text[Length(Memo1.Lines.Text)] = #10)) then
  begin
  // this is for a enter key press
  s := Memo1.Lines.Text;
  SetLength(s, Length(s)-2);
  Memo1.Lines.Text := s;
  Memo1.SelStart := Length(Memo1.Lines.Text);
  Memo1.SelLength := 0;
  Exit;
  end;

if Memo1.Lines.Count > MaxLines then
  begin
  s := Memo1.Lines.Text;
  i := 0;
  pGet := @s[1];
  while i < MaxLines do
    begin
    // this is for a Paste of more than several lines of text
    pGet := StrScan(pGet, #13);
    if (pGet = nil) then Break;
    Inc(pGet);
    Inc(i);
    if (pGet^ = #0) then Break;
    end;

  if pGet <> nil then
    begin
    i := Integer(pGet) - Integer(@s[1]);
    SetLength(s, i-1);
    end else
    SetLength(s, Length(s)-1); // for an auto line break without #10

  Memo1.Text := s;
  Memo1.SelStart := Length(Memo1.Lines.Text);
  Memo1.SelLength := 0;
  end;

end;

 - - - - - - - - - - - - - - - - - - - -

this seems to work for me and will also keep the lines to max even for a text paste into the memo
0
 

Author Comment

by:voodoo22
Comment Utility
(Slick812) Thanks for the help your code does all I need it to do.

(xxflip) I gave slick the points for the question because his solution is what I needed but just so you don't feel you have done this for nothing I am upping the points for the question and giving you points for your input as well...and thanks for your help

(Ivanov_G) Same thing as I told xxflip.

0
 
LVL 2

Expert Comment

by:xxflip
Comment Utility
Thanks for the points. I do this because I like to help and also because it is the best place to find other ways of doing things (mine is not always the best), thus enabling me to improve my skills.
0

Featured Post

Better Security Awareness With Threat Intelligence

See how one of the leading financial services organizations uses Recorded Future as part of a holistic threat intelligence program to promote security awareness and proactively and efficiently identify threats.

Join & Write a Comment

Suggested Solutions

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 Raise your hands if you were as upset with FireMonkey as I was when I discovered that there was no TListview.  I use TListView in almost all of my applications I've written, and I was not going to compromise by resorting to TStringGrid…
This video gives you a great overview about bandwidth monitoring with SNMP and WMI with our network monitoring solution PRTG Network Monitor (https://www.paessler.com/prtg). If you're looking for how to monitor bandwidth using netflow or packet s…
In this tutorial you'll learn about bandwidth monitoring with flows and packet sniffing with our network monitoring solution PRTG Network Monitor (https://www.paessler.com/prtg). If you're interested in additional methods for monitoring bandwidt…

772 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

Need Help in Real-Time?

Connect with top rated Experts

15 Experts available now in Live!

Get 1:1 Help Now