Home > Net >  How do I set the TEditMask format to both automatically insert spaces and use the spaces in pasted t
How do I set the TEditMask format to both automatically insert spaces and use the spaces in pasted t

Time:03-10

Given this text for the EditMask property of a TMaskEdit control,

>AAAAA_AAAAA_AAAAA_AAAAA_AAAAA_AAAAA_A;0;_

When the user types, a space is automatically inserted after every 5 characters.

However, if the user pastes in text that already contains the spaces (for example, copied from an email we sent them), then each space uses up one of the required characters and the last 5 characters of the text are lost.

Is there a way to identify a particular character in the TEditMask so it is either empty or the specific character (in this case, a space)? Or is there a different control I could use?

CodePudding user response:

Don't use TMaskEdit and its horrible optics and limitations. Since the text you want to operate on is rather short you can use a TEdit directly and react upon changes to its text:

  • Always make the text uppercase.
  • Don't rely on keyboard versus mouse input.
  • Kill all spaces on purpose and put them anywhere you want for optic reasons.

Also don't make the mistake to use several TEdits for each block of text, as that will disrupt anyone who wants to paste the clipboard content of the long serial(?) at once - I've seen software installations doing this and it was always a pain.

Have an empty form, add a TEdit and make this its OnChange event:

procedure TForm1.Edit1Change( Sender: TObject );
var
  edt: TEdit;  // Easier access
  sText: String;  // Easier access
  iLen, iPos, iCur: Integer;  // Text length, Character to inspect, Text cursor position
begin
  // Sender might be nil in rare conditions
  if not (Sender is TEdit) then exit;
  edt:= Sender as TEdit;

  // Empty texts don't need our care
  iLen:= Length( edt.Text );
  if iLen= 0 then exit;

  // I guess you always want big letters
  sText:= UpperCase( edt.Text );

  // Kill all spaces, so it doesn't matter how many are in there
  iCur:= edt.SelStart;  // Remember text cursor position
  iPos:= Pos( ' ', sText );  // Find first occurance
  while iPos> 0 do begin
    Delete( sText, iPos, 1 );
    Dec( iLen );
    if iCur>= iPos then Dec( iCur );  // Was text cursor after that spot? Should move, too.
    iPos:= Pos( ' ', sText );  // Find next occurance
  end;

  iPos:= 5;  // Character of the text to inspect
  while iPos< iLen do begin  // Much better than "<=", credit: Tom Brunberg
    if sText[iPos  1]<> ' ' then begin  // Next character is not a space?
      Insert( ' ', sText, iPos  1 );  // Insert space
      if iCur> iPos then Inc( iCur );  // Was text cursor after that spot? Should move, too.
      Inc( iLen );  // Text size has been increased by us
    end;

    Inc( iPos, 6 );  // Go to next end of a "block"
  end;

  edt.OnChange:= nil;  // Otherwise setting .Text will trigger this event again
  edt.Text:= sText;  // We're done
  edt.OnChange:= Edit1Change;
  edt.SelStart:= iCur;  // Recover/fix text cursor
end;

Successfully tested on D7:

TEdit with fixed spaces in text

Deleting only single characters feels weird, tho, and does not work when the last one is a space. I'll leave it to you to make it perfect.

  • Related