MEGA Search
20.3 Million


Sign Up
From: Gary  
Subject: Validating & Pasting into TEdit
NewsGroup: borland.public.delphi.vcl.components.using.win32
Date Posted: 3-Jun-2005 at 15:33:30 PST
It's pretty simple to handle the OnKeyPress event to restrict the user 
to typing integers in a TEdit.  But what about when the user pastes 
something from the clipboard?  Sure, I can handle the OnChange event, 
even though the code is not pretty.  I not only have to check each 
character, but I have to check for a leading - sign and check that the 
value doesn't exceed integer bounds.  And since OnChange is fired after 
each key press, it's got to be smart enough not to discard the entire 
contents when it fails validation.  But unlike OnKeyPress, OnChange 
doesn't know which character was just inserted, so what do I discard?

It seems that these two events work against each other or do double the 
effort, because the OnChange event will get fired after every key press, 
and I've already validated key presses. There's no apparent way to 
determine if OnChange is fired due to a paste or a key press.

Is there a simple answer to validating clipboard pastes?

From: Gary  
Subject: Re: Validating & Pasting into TEdit
NewsGroup: borland.public.delphi.vcl.components.using.win32
Date Posted: 4-Jun-2005 at 8:40:31 PST
That's perfect, Peter.  Thanks!

....Gary

From: Peter Below (TeamB)  
Subject: Re: Validating & Pasting into TEdit
NewsGroup: borland.public.delphi.vcl.components.using.win32
Date Posted: 4-Jun-2005 at 11:3:20 PST
In article <42a0b0a4$2@newsgroups.borland.com>, Gary wrote:
> It's pretty simple to handle the OnKeyPress event to restrict the user 
> to typing integers in a TEdit.  But what about when the user pastes 
> something from the clipboard?  Sure, I can handle the OnChange event, 
> even though the code is not pretty.  I not only have to check each 
> character, but I have to check for a leading - sign and check that the 
> value doesn't exceed integer bounds.  

For more complex validation you need to create a custom descendent of TEdit 
(or TCustomEdit) and handle some messages. Search the newsgroup archives 
(see signature below) for TNumberEdit, that should turn up a rather lengthy 
message on how to write a custom edit with validation i posted a number of 
years ago.

Or play with this unit:

unit ValidatableEdits;

interface

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

type
  TCharSet = Set of Char;

  TBaseValidatableEdit = class(Tedit)
  private
    { Private declarations }
    FLastContent: String;
    FLastPosition: Integer;
    FAllowedChars: TCharset;

    Procedure SetAllowedChars; virtual; abstract;
  protected
    { Protected declarations }
    Procedure SaveState;
    Procedure RestoreState;
    Function IsValidChar( ch: Char ): Boolean; virtual;
    Function Validate: Boolean; virtual; abstract;

    Procedure WndProc( Var msg: TMessage ); override;

    property AllowedChars: TCharset read FAllowedChars write FAllowedChars;
    property LastContent: String read FLastContent;
    property LastPosition: Integer read FLastPosition;
  public
    { Public declarations }
    Constructor Create( aOwner: TComponent ); override;
  end;

  TIntegerEdit = Class( TBaseValidatableEdit )
  private
    Procedure SetAllowedChars; override;
    function GetAllowNegative: Boolean;
    procedure SetAllowNegative(const Value: Boolean);
  protected
    Function Validate: Boolean; override;
  published
    { Published declarations }
    property AllowNegative: Boolean
      read GetAllowNegative write SetAllowNegative default True;
  end;

  TFloatEdit = Class( TIntegeredit )
  private
    Procedure SetAllowedChars; override;
  protected
    Function Validate: Boolean; override;
  end;

procedure Register;

implementation

procedure Register;
begin
  RegisterComponents('PBGoodies', [TIntegerEdit, TFloatEdit]);
end;

{ TBaseValidatableEdit }

constructor TBaseValidatableEdit.Create(aOwner: TComponent);
begin
  inherited;
  ControlStyle := Controlstyle - [csSetCaption];
  SetAllowedChars;
end;


function TBaseValidatableEdit.IsValidChar(ch: Char): Boolean;
begin
  Result := ch In FAllowedChars;
end;

procedure TBaseValidatableEdit.RestoreState;
begin
  Text := FLastContent;
  SelStart := FLastPosition;
end;

procedure TBaseValidatableEdit.SaveState;
begin
  FLastContent := Text;
  FLastPosition := SelStart;
end;

procedure TBaseValidatableEdit.WndProc(var msg: TMessage);
begin
  Case msg.msg of
    WM_CHAR: Begin
        If IsValidChar( Chr( msg.wparam )) Then Begin
          SaveState;
          inherited;
          If not Validate Then
            RestoreState;
        End { If }
        Else
          If msg.wparam < 32 Then
            { Pass on control characters or Ctrl-C, Ctrl-V, Ctrl-X stop to 
work }
            inherited; 
      End; { Case WM_CHAR }
    WM_PASTE: Begin
        SaveState;
        inherited;
        If not Validate Then
          RestoreState;
      End; { WM_PASTE }
  Else
    inherited;
  End; { Case }
end;

{ TIntegeredit }

function TIntegerEdit.GetAllowNegative: Boolean;
begin
  Result := IsValidChar( '-' );
end;

procedure TIntegerEdit.SetAllowedChars;
begin
  AllowedChars := ['0'..'9','-',#8];
end;

procedure TIntegerEdit.SetAllowNegative(const Value: Boolean);
begin
  If Value Then
    Include( FAllowedChars, '-' )
  Else
    Exclude( FAllowedChars, '-' );
end;

{$HINTS OFF}{ Hide hint for "i not used" in method below. }
function TIntegerEdit.Validate: Boolean;
var
  err, i: Integer;
begin
  Val( Text, i, err );
  Result := (err = 0) or (GetTextLen = 0) or (Text = '-');
end;
{$HINTS ON}

{ TFloatEdit }

procedure TFloatEdit.SetAllowedChars;
begin
  inherited;
  AllowedChars := AllowedChars + [DecimalSeparator];
end;

function TFloatEdit.Validate: Boolean;
begin
  try
    StrToFloat( text );
    Result := true;
  except
    Result := (GetTextLen = 0) or (Text = '-');
  end;
end;

end.

TFloatEdit.Validate should be rewritten to use TryStrToFloat, of course.

--
Peter Below (TeamB)  
Use the newsgroup archives :
http://www.mers.com/searchsite.html
http://www.tamaracka.com/search.htm
http://groups.google.com
http://www.prolix.be



From: Ben Hochstrasser  
Subject: Re: Validating & Pasting into TEdit
NewsGroup: borland.public.delphi.vcl.components.using.win32
Date Posted: 4-Jun-2005 at 0:22:45 PST
Remy Lebeau (TeamB) wrote:

> How about intercepting the WM_PASTE and/or WM_SETTEXT messages and
> validate/modify the text before it is actually assigned?

That might work. Although I am not sure whether tampering with pasted text 
is the right approach, not in a technical sense but in a usability (and 
plausability, for the user) sense. Personally I prefer that an application 
boos and hisses when I paste something silly instead of silently mutilating 
my input.

-- 
Ben

From: Remy Lebeau \(TeamB\)  
Subject: Re: Validating & Pasting into TEdit
NewsGroup: borland.public.delphi.vcl.components.using.win32
Date Posted: 3-Jun-2005 at 15:12:44 PST
"Ben Hochstrasser"  wrote in message
news:Xns966AF179DC28Bbhoc@207.105.83.66...

> Won't help with pasted text, unfortunately.

How about intercepting the WM_PASTE and/or WM_SETTEXT messages and
validate/modify the text before it is actually assigned?


Gambit



From: Kjell Rilbe  
Subject: Re: Validating & Pasting into TEdit
NewsGroup: borland.public.delphi.vcl.components.using.win32
Date Posted: 3-Jun-2005 at 23:59:7 PST
Gary wrote:

> Is there a simple answer to validating clipboard pastes?

Not really, but in one (set of) application(s) I have created a method 
that silently remove certain characters that are not allowed while 
retaining caret (cursor) position. It's a bit meesy but it works. Do you 
want to send you some hints?

To avoid recurson when modifying the content in OnChange (via Undo or 
otherwise) as well as OnKeyPress and OnChange clashes, use flag 
variables. Something like this:

type
   TMyForm = class(TForm)
   ...
   private
     FInEditKeyPress: Boolean;
     FInEditChange: Boolean;
   ...
   end;

procedure TMyForm.Create;
begin
   FInEditKeyPress:=False;
   FInEditChange:=False;
end;

procedure TMyForm.EditChange;
begin
   if not FInEditChange then begin
     FInEditChange:=True;
     try
       { Do whatever you need to do here... }
     finally
       FInEditChange:=False;
     end;
   end;
end;

procedure TMyForm.EditKeyPress;
begin
   if not FInEditKeyPress then begin
     FInEditKeyPress:=True;
     try
       { Do whatever you need to do here... }
     finally
       FInEditKeyPress:=False;
     end;
   end;
end;

Hope it helps.

Kjell
-- 
---------------------------------------------------------------------------
Kjell Rilbe
Home: +46 8 7610734
Cell: +46 733 442464
---------------------------------------------------------------------------
"If there's a price for bein' me, that's one I'll have to pay"
Aaron Tippin
---------------------------------------------------------------------------

From: Ben Hochstrasser  
Subject: Re: Validating & Pasting into TEdit
NewsGroup: borland.public.delphi.vcl.components.using.win32
Date Posted: 3-Jun-2005 at 23:44:16 PST
Remy Lebeau (TeamB) wrote:

> How about giving the TEdit window the ES_NUMBER style and let the OS
> handle all of the user input on your behalf?

Won't help with pasted text, unfortunately.

-- 
Ben

From: Remy Lebeau \(TeamB\)  
Subject: Re: Validating & Pasting into TEdit
NewsGroup: borland.public.delphi.vcl.components.using.win32
Date Posted: 3-Jun-2005 at 14:22:9 PST
"Gary"  wrote in message
news:42a0b0a4$2@newsgroups.borland.com...

> Is there a simple answer to validating clipboard pastes?

How about giving the TEdit window the ES_NUMBER style and let the OS handle
all of the user input on your behalf?


Gambit



From: Ben Hochstrasser  
Subject: Re: Validating & Pasting into TEdit
NewsGroup: borland.public.delphi.vcl.components.using.win32
Date Posted: 3-Jun-2005 at 22:54:11 PST
Gary wrote:

> The problem with the OnExit approach is that the user can see the text 
> they paste before leaving the edit.

And? As well the should (after all the user pasted the text so there's 
no secret to keep...).

I think that a distinct "problem alert" is better than silently omitting 
certain characters from being pasted - When I paste text somewhere I assume 
all of it is pasted, not just the "politically correct" parts, and move on 
to more rewarding tasks such as pressing [Enter]. I wouldn't like the 
thought at all that a piece of software modifies my input without warning 
me.

-- 
Ben

From: Gary  
Subject: Re: Validating & Pasting into TEdit
NewsGroup: borland.public.delphi.vcl.components.using.win32
Date Posted: 3-Jun-2005 at 15:57:18 PST
My quick experiment with using Undo in OnChange was a failure.  When I 
pasted text into the control, it flashed a bunch of times and then 
bombed with a stack overflow.  Must be some heavy recursion going on there.

The problem with the OnExit approach is that the user can see the text 
they paste before leaving the edit.

Ben Hochstrasser wrote:
> Mark Williams wrote:
> 
> 
>>Don't know what you're trying to do but perhaps a TMaskEdit is the
>>answer. 
> 
> 
> Or simply do a val() against edit1.text upon OnExit(), and if you don't 
> like the result, beep, set edit1.text to the result of the val() evaluation 
> and set the focus back to edit1.
> 
> I wouldn't mess with "live" corrections in OnChange. OnKeyPress is okay, 
> however.
> 

From: Ben Hochstrasser  
Subject: Re: Validating & Pasting into TEdit
NewsGroup: borland.public.delphi.vcl.components.using.win32
Date Posted: 3-Jun-2005 at 21:51:30 PST
Mark Williams wrote:

> Don't know what you're trying to do but perhaps a TMaskEdit is the
> answer. 

Or simply do a val() against edit1.text upon OnExit(), and if you don't 
like the result, beep, set edit1.text to the result of the val() evaluation 
and set the focus back to edit1.

I wouldn't mess with "live" corrections in OnChange. OnKeyPress is okay, 
however.

-- 
Ben

From: Gary  
Subject: Re: Validating & Pasting into TEdit
NewsGroup: borland.public.delphi.vcl.components.using.win32
Date Posted: 3-Jun-2005 at 15:50:7 PST
Thanks, Mark.  I don't like the feel or look of TMaskEdit.  I'll 
experiment with the Undo method.

Mark Williams wrote:
>>But unlike OnKeyPress, OnChange
>>doesn't know which character was just inserted, so what do I discard?
> 
> 
> Edit1.undo will restore it to the condition immediately before the offending
> change be it keypress or paste.
> 
> 
>>Is there a simple answer to validating clipboard pastes?
> 
> 
> Don't know what you're trying to do but perhaps a TMaskEdit is the answer.
> 
> Cheers,
> 
> Mark
> 
> 

From: Mark Williams  
Subject: Re: Validating & Pasting into TEdit
NewsGroup: borland.public.delphi.vcl.components.using.win32
Date Posted: 3-Jun-2005 at 15:37:7 PST
>But unlike OnKeyPress, OnChange
> doesn't know which character was just inserted, so what do I discard?

Edit1.undo will restore it to the condition immediately before the offending
change be it keypress or paste.

> Is there a simple answer to validating clipboard pastes?

Don't know what you're trying to do but perhaps a TMaskEdit is the answer.

Cheers,

Mark



From: Koms Bomb  
Subject: Re: Validating & Pasting into TEdit
NewsGroup: borland.public.delphi.vcl.components.using.win32
Date Posted: 6-Jun-2005 at 11:5:28 PST
> My quick experiment with using Undo in OnChange was a failure.  When I
> pasted text into the control, it flashed a bunch of times and then
> bombed with a stack overflow.  Must be some heavy recursion going on
there.

Because Undo triggered OnChange again do it's in a dead loop.
Don't Undo in OnChange. Instead of that, in OnChange, PostMessage (not
SendMessage)
a message to yourself, then in the message handler Undo it.