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 TEdit
s 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:
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.