Lazarus

Programming => LCL => Topic started by: EganSolo on March 03, 2021, 08:07:43 am

Title: [SOLVED] Is this a bug in TMaskEdit?
Post by: EganSolo on March 03, 2021, 08:07:43 am
To see what I'm talking about, you simply have to

Code: Pascal  [Select][+][-]
  1. Procedure TForm1.FormCreate(Sender: TObject);
  2. Begin
  3.   With MaskEdit1 do
  4.   begin
  5.     EditMask := '!\(000\)-000-0000;0;_';
  6.     Caption  := '6142345678';
  7.     //Comment the line above and uncomment the line below if you want to test it with Text instead of Caption: same thing.
  8.    //Text := '6142345678';
  9.   End;
  10. end;    
  11.  

Run the program, and you'll see the output as seen in the attached image: The component is properly displaying the phone number as (614)-234-5678 but it's highlighting '(614)-234-' instead of highlighting the entire string. The length of '(614)-234-' is ten which is the length of the phone number, so it seems that it's behaving as if it's editing a non-masked string.

Curiously, SelectAll is not overridden in TCustomMaskEdit and its implementation in TCustomEdit reads as follows:

Code: Pascal  [Select][+][-]
  1. procedure TCustomEdit.SelectAll;
  2. begin
  3.   if Text <> '' then
  4.   begin
  5.     SetSelStart(0);
  6.     SetSelLength(UTF8Length(Text));
  7.   end;
  8. end;
  9.  

That code is selecting Text. If I'm reading the documentation of TMaskEdit at https://lazarus-ccr.sourceforge.io/docs/lcl/maskedit/tmaskedit.html (https://lazarus-ccr.sourceforge.io/docs/lcl/maskedit/tmaskedit.html), Text is
The Text string that is to be masked (or not). If that's the case, then shouldn't we override SelectAll in TCustomMaskEdit and have it select the masked text?
 
Title: Re: Is this a bug in TMaskEdit?
Post by: Bart on March 03, 2021, 06:26:25 pm
SelectAll should select all visible text.
It obviously doesn't, which is a bug.
I'll try and fix it.

Bart
Title: Re: Is this a bug in TMaskEdit?
Post by: Bart on March 03, 2021, 06:53:01 pm
Fixed in r64741.
Please test (with trunk) and report back.

Bart
Title: Re: [SOLVED] Is this a bug in TMaskEdit?
Post by: EganSolo on March 03, 2021, 07:19:00 pm
Thanks, Bart. It works!  :D
Title: Re: [SOLVED] Is this a bug in TMaskEdit?
Post by: Bart on March 03, 2021, 08:45:30 pm
This bug has been there for ages.
Nobody spotted it before.

Bart
Title: Re: [SOLVED] Is this a bug in TMaskEdit?
Post by: EganSolo on March 03, 2021, 11:30:16 pm
I've noticed another minor bug, an annoyance really,  that may be fixed with a slight mod to what you just did:

Using the mask: !\(000\)-000-0000;0;_
Set Text to any phone number (123-456-7890)

As soon as the edit mask has the focus, it will now (correctly) highlight the entire number with all the characters in it.

Hit backspace: the cursor will settle on the left paren so that if you type a digit, the edit mask will gobble it and it won't show up. You have to first hit the right arrow to move the cursor to the first digit position and then enter a digit.

The fix would be to move the cursor to the first pos that accepts input

Let me know if you'd like me to send you a ready-made code that demonstrates that behavior.
Title: Re: [SOLVED] Is this a bug in TMaskEdit?
Post by: Bart on March 04, 2021, 08:16:15 pm
Hit backspace: the cursor will settle on the left paren so that if you type a digit, the edit mask will gobble it and it won't show up. You have to first hit the right arrow to move the cursor to the first digit position and then enter a digit.
It is supposed to move to the first editable position, so this is a bug.

Bart
Title: Re: [SOLVED] Is this a bug in TMaskEdit?
Post by: Bart on March 04, 2021, 08:19:29 pm
using 000 is will fault, and there is no way that I can see to catch it? It pops up a fault screen either way in or out of debug mode and where would you put a Try and catch on this ? 8)

Well, this all is modellead after the Delphi behaviour (in some aspects it's even worse, trust me).
Please complain to them (not to me).

You can handle the exceptions in a Application.OnException handler.

Bart
Title: Re: [SOLVED] Is this a bug in TMaskEdit?
Post by: Bart on March 04, 2021, 08:51:47 pm
Hit backspace: the cursor will settle on the left paren so that if you type a digit, the edit mask will gobble it and it won't show up. You have to first hit the right arrow to move the cursor to the first digit position and then enter a digit.
It is supposed to move to the first editable position, so this is a bug.

Fixed in r64744.
Please test.

Bart
Title: Re: [SOLVED] Is this a bug in TMaskEdit?
Post by: winni on March 04, 2021, 08:57:28 pm
Hi!

TMaskedit is scrap since Delphi 1.
And with every Delphi version they fixed some bugs.
And created  some new bugs.

We are talking about a timespan of 25 years!

If someone is courageous:
Make a new design and a new TMaskedit.
Without bugs. So not Delphi compatible.
That would help a lot of people.
 
Winni
Title: Re: [SOLVED] Is this a bug in TMaskEdit?
Post by: Bart on March 04, 2021, 09:05:31 pm
Feel free to implement it.

The basic design flaw IMO is that it raises exceptions, which you can only catch if you implement an Application.OnException handler.
A simple OnValidateError event would have given the programmer a better change of fighting the beast.

And why EDBEditError and not simply EMaskEditError?

Somebody suggested once tha have a similar control where "EditMask" could be a RegEx.

Bart
Title: Re: [SOLVED] Is this a bug in TMaskEdit?
Post by: winni on March 04, 2021, 09:26:38 pm
Feel free to implement it.

Bart

Don't try to teach an old horse new tricks ...

My workaround is since 25 years the same:

Take a simple TEdit.
On every onChange start a little parser for your current needs and see if the change is allowed.
If not take the string before.
Not realy a big trick but before I get a gastric ulcer because of TMaskEdit ...

Winni
Title: Re: [SOLVED] Is this a bug in TMaskEdit?
Post by: Bart on March 04, 2021, 09:38:42 pm
In the old days I had an application made in D1, later D3 that relied heavily on TMaskEdit to enforce correct user input (floats).
It was in fact fool proof.

Then I made the switch to Lazarus and started to re-implement my Delphi apps in Lazarus (no proper conversion tool then).
TMaskEdit was non-functional to say it politely.
A simple Text := 'Something' could raise an exception.

So I sat out and started to almost re-implement it.
Just by black-boxing the behaviour against D3.

I made some subtle deviations from Delphi (e.g. OnExit fires before validation, so you can validate yourself).
Later on I added some nice features which Delphi does not have, like a mask for hexadecimal input, the possibility to temporarily disable the mask (and later re-enable it).

After I had done all that, I started out re-implementing my Delphi app, only to find out we (Lazarus) have a TFloatSpinEdit, which Delphi (3) does not.
So, I abandoned TMaskEdit and have not found a use for it since.

Bart
Title: Re: [SOLVED] Is this a bug in TMaskEdit?
Post by: Bart on March 05, 2021, 01:37:56 pm
As I wrote, raising excpetions on validation error is a design flaw IMO.
But then, we strive to be Delphi compatible.

You might wat to create a patch that implemenst e.g. a OnValidateErro event, and call that instead of raising an exception.
All this of course only if controlled by some property and defaulting to old behaviour.

We can extend our implementation beyond that of Delphi (and we already have).

To be honest, I would like to know how many users actually use a TMaskEdit (or it's DB counterpart).

Bart
Title: Re: [SOLVED] Is this a bug in TMaskEdit?
Post by: winni on March 06, 2021, 09:43:00 pm

To be honest, I would like to know how many users actually use a TMaskEdit (or it's DB counterpart).

Bart

The last time around 1997 (Delphi). Then I gave up.

Winni
Title: Re: [SOLVED] Is this a bug in TMaskEdit?
Post by: Bart on March 06, 2021, 11:10:32 pm
using a MASK := 000-000-0000;0;_;
hitting the backspace causes the first initial input to land on the second digit.
I cannot reporduce that.

Also there seems to be something wrong with displaying unwanted tail items in the EDIT, like the ";" etc

Indeed that is not Delphi compatible.

This is what I concluded from (I think) Delphi3 help files:

A value for SpaceChar is only valid if also a value for MaskSave is specified
(as by Delphi specifications), so Mask must be at least 4 characters
These must be the last 2 or 4 characters of EditMask (and there must not be
an escape character in front!)

So if a mask ends in ;0;_ then SpaceChar will be _
If a mask ends in ;0; the behaviour is undefined IMO.

It seems like Delphi (7) simply ignores if the last ; if a mask ends in ;
e.g. 'ccc;' is treated as 'ccc' (which is the same as 'ccc;1;_')
'ccc;0;' is treated as 'ccc;0;_'
But then 'ccc;0;_;' the first ; is treated as a maskliteral and the last ; is discarded, the 0 is treated as MaskNoSave
And 'ccc;X;_;' the X is not treated as "not MaskNoSave" (normally anything other than 0 is treated as if it were 1 in that part of the mask).

All in all, it is utterly inconsistent.
At least I cannot mak head or tails of it.

In or implementation the rules are relatively simple:
If the mask ends in ';' + SomeAnsiChar + ';' + SomeAnsiChar and there is no '\' in front of the first ';' then you have defined a value for SpaceChar and wether or not the mask is included when you retrieve the Text
You can omit the last 2 (SomeAnsiChar + ';') and then SpaceChar will be '_' by default.

If you do anything else, all of the ';' will be treated as a mask lilteral.

So unless you can come up with a consistent algorithm how to treat a mask that ends in a ';', I'm not willing to change it ATM.

Bart
Title: Re: [SOLVED] Is this a bug in TMaskEdit?
Post by: Bart on March 06, 2021, 11:15:36 pm
The only issue I have with it is it does not have an OnError event, nor does Delphi last time I checked so its kind of hard to capture the error and make a choice on what to do with it, ignore the error and fill in some defaults, Exit with an message box or somehow force it to about its editing back to the original text that was there upon entry..

As I sated before: you can do that in Application.OnException.
There you can inspect the value of either Text or EditText and decide what you want to do.
My MaskEdit test suite uses this:

Code: Pascal  [Select][+][-]
  1. procedure TForm1.AppException(Sender: TObject; E: Exception);
  2. begin
  3.   if (E is EDBEditError) then
  4.   begin
  5.     ShowMessage(E.Message);
  6.     if (Sender is TCustomMaskEdit) then TCustomMaskEdit(Sender).SetFocus;
  7.   end
  8.   else
  9.     Application.ShowException(E);
  10. end;

Bart
Title: Re: [SOLVED] Is this a bug in TMaskEdit?
Post by: Bart on March 07, 2021, 10:18:08 pm
Seriously you can't see the bug in the MASK ?

You're right.

Fixed in r64767.
Thanks for noticing.

Bart
Title: Re: [SOLVED] Is this a bug in TMaskEdit?
Post by: Bart on March 08, 2021, 10:25:48 pm
Seems to work with both 0000 and !(0000), I am sure the others will appreciate you

It's kind of my baby ...

Bart
Title: Re: [SOLVED] Is this a bug in TMaskEdit?
Post by: Bart on March 09, 2021, 07:11:30 pm
The only issue I have with it is it does not have an OnError event...

I implemented that in r64773.
It is experimental and absolutely not Delphi compatible.
As such, the option is not published, nor is the corresponding event.
You'll have to assign it in code.

Bart
Title: Re: [SOLVED] Is this a bug in TMaskEdit?
Post by: Bart on March 10, 2021, 09:35:50 am
That would not make much sense to me.
In the event you can do whatever you would like to do: show an errormessage, silently re-focus the maskedit, correct the text in the control, ask the user to pay you in bitcoins, format his harddrive, or do just nothing (in effect just ignoring the validation)...
Infinite possibilities.

A "var Accept" parameter would make sense if, when user does not accept, it would automatically reset the control to some previous state (what state would that be then?).
I'll investigate if that is possible at all.

I thought of adding a paramter indicating at what index in the control the first "mismatch" was, but implementing that would need yet another private field, which feels a bit hackish.
Even nicer might be to also indicate what the reason for the validation error was. Something like: at index 2: expected: number, found: blank. But that feels like overkill. This information then would also have o be propagated if the Exception method is used, which would be Delphi incompatible as well.

In the end, the reason for implementing this solution, only ever was to avoid having to use exceptions (that can only be handled in a OnException handler).

Bart
Title: Re: [SOLVED] Is this a bug in TMaskEdit?
Post by: Bart on March 10, 2021, 09:54:20 am
OK, while it is technically possible to implement a "var Accept" or similar parameter, the question then would be what to do if Accept is False.
Reset would be a possible solution, but Clear is possible too.
Mind you, that the TMaskEdit instance itself would then have to decide what the proper action would be.
If I implement it as "Reset if Accept is False", then other users can argue or request that "Clear if Accept is False" or "Set Text to a user defined Text if Accept is False" (like e.g. TFileNameEdit does) suits their applicartion/use case better.

Also: does "Accept = True" make much sense? If so, then why would you use a TMaskEdit in the first place?

So, for the time being, I don't think I will implement it this way.

Bart
TinyPortal © 2005-2018