Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to get notification when text pasted from clipboard into an edit box exceeds the maximum length?

Tags:

delphi

I need to show a message to the user when text pasted from the clipboard into a TEdit control exceeds its maximum allowed length. But I would not like the program to check every time a new letter is typed, only when text is pasted.

How would I do this?

like image 349
niksrb Avatar asked Apr 20 '18 08:04

niksrb


3 Answers

Subclass the edit class and listen for the WM_PASTE message. For example (for Unicode Delphi):

uses
  Vcl.Clipbrd;

type
  TEdit = class(Vcl.StdCtrls.TEdit)
  private
    procedure WMPaste(var Msg: TWMPaste); message WM_PASTE;
  end;

implementation

procedure TEdit.WMPaste(var Msg: TWMPaste);
begin
  if (MaxLength > 0) and (Length(Clipboard.AsText) > MaxLength - GetTextLen + SelLength) then
    ShowMessage('Text is too long!');
  inherited;
end;

Another, little more efficient WinAPI variant (which doesn't copy the clipboard buffer but just queries its size), could be (also for Unicode Delphi):

type
  TEdit = class(Vcl.StdCtrls.TEdit)
  private
    procedure WMPaste(var Msg: TWMPaste); message WM_PASTE;
  end;

implementation

procedure TEdit.WMPaste(var Msg: TWMPaste);
var
  Data: THandle;
begin
  if (MaxLength > 0) and OpenClipboard(0) then
  try
    Data := GetClipboardData(CF_UNICODETEXT);
    if (Data <> 0) and ((GlobalSize(Data) div SizeOf(Char)) - 1 > MaxLength - GetTextLen + SelLength) then
      ShowMessage('Text is too long!');
  finally
    CloseClipboard;
  end;
  inherited;
end;

If you wanted to prevent the text from being pasted into the control, remove the inherited calls from the above examples.

like image 105
Victoria Avatar answered Oct 19 '22 01:10

Victoria


Subclass the TEdit to handle the EN_MAXTEXT notification:

Sent when the current text insertion has exceeded the specified number of characters for the edit control. The text insertion has been truncated.

This applies to typing as well as pasting, and takes text selection into account for you. For example:

unit Unit1;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls;

type
  TEdit = class(Vcl.StdCtrls.TEdit)
  private
    procedure CNCommand(var Message: TWMCommand); message CN_COMMAND;
  end;

  TForm1 = class(TForm)
    Edit1: TEdit;
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TEdit.CNCommand(var Message: TWMCommand);
begin
  inherited;
  if Message.NotifyCode = EN_MAXTEXT then
    ShowMessage('Too much text!');
end;

end.

If you only want to handle pasting, then catch WM_PASTE to set a flag before calling inherited, then clear the flag when inherited exits, and if EN_MAXTEXT is issued while the flag is set then act accordingly:

unit Unit1;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls;

type
  TEdit = class(Vcl.StdCtrls.TEdit)
  private
    FIsPasting: Boolean;
    procedure CNCommand(var Message: TWMCommand); message CN_COMMAND;
    procedure WMPaste(var Message: TMessage); message WM_PASTE;
  end;

  TForm1 = class(TForm)
    Edit1: TEdit;
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TEdit.CNCommand(var Message: TWMCommand);
begin
  inherited;
  if (Message.NotifyCode = EN_MAXTEXT) and FIsPasting then
    ShowMessage('Too much text!');
end;

procedure TEdit.WMPaste(var Message: TMessage);
begin
  FIsPasting := True;
  try 
    inherited;
  finally
    FIsPasting := False;
  end;
end;

end.
like image 27
Remy Lebeau Avatar answered Oct 19 '22 01:10

Remy Lebeau


Here you go:

unit Unit1;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Clipbrd;

type
  TPasteEdit = class(TEdit)
    private
      FMaxPaste: Integer;
      procedure WMPaste(var Message: TWMPaste); message WM_PASTE;
    protected
    public
      constructor Create(AOwner: TComponent); override;
    published
      property MaxPaste: Integer read FMaxPaste write FMaxPaste default 0;
      //You can define it or use MaxLength as well
  end;
  TForm1 = class(TForm)
    procedure FormCreate(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}



{ TPastEdit }

constructor TPasteEdit.Create(AOwner: TComponent);
begin
  inherited;
  FMaxPaste:= 0;
end;

procedure TPasteEdit.WMPaste(var Message: TWMPaste);
begin
  if Length(Clipboard.AsText) > FMaxPaste then
    ShowMessage('The text you paste is too long!') // Call inherited if you want to paste anyway
      else
        inherited;
end;

procedure TForm1.FormCreate(Sender: TObject);
Var
  PasteEdit: TPasteEdit;
begin
  PasteEdit:= TPasteEdit.Create(Self);
  PasteEdit.Parent:= Self;
  PasteEdit.MaxPaste:= 3;
end;

end.
like image 31
Ilyes Avatar answered Oct 19 '22 03:10

Ilyes