Although you do not specify exactly what does not work, hereby some answers on why this does not work, because it is pretty obvious what you want. Typical use is entering a registration key.
You use StrToFloat
to convert the Edit text into a numeric value. Since you want the value to be between 1100 and 1500, you should use StrToInt
, although that is not necessary. However, there is a problem with the use of this function, because the Text
property of an empty edit is ''
, which cannot be converted to a number and would cause an EConvertError
exception that can easily be avoided. Use TryStrToInt
or StrToIntDef
to prevent this error.
Your conditional expression is misleading. Instead of
if (1500 < A) or (A < 1100) then
use
if (A < 1100) or (A > 1500) then
which is much more readable. You can also use the InRange
function from the System.Math
unit:
if not InRange(A, 1100, 1500) then
whatever you prefer.
You check this condition on every keystroke in the Edit, because OnChange
fires on every single edit. Now, when you start entering a correct number by typing 1, the condition will be evaluated true, (the message will popup (but I understand that is a temporarily debugging feature)), and the Edit will be set focussed. But it already was, so that is unnecessary.
When you select the next Edit control by pressing TAB, the OnChange
event will not fire, because nothing changed besides losing focus. The solution is to check the condition in the OnExit
event. This is the solution for the previous remark as well.
A drawback of relying on validation in OnExit
is that that event might not fire in case of dialog closure. But that could or would not be a problem because exiting a dialog with ESC or the dialog's close button, typically indicates that you are cancelling the operation. But remember.
Bonus
Hereby an intuitive implementation that will solve various concerns. Link all these event handlers to all Edit controls:
const
MinValue = 1100;
MaxValue = 1500;
procedure TForm1.EditChange(Sender: TObject);
var
Edit: TEdit absolute Sender;
begin
if Length(Edit.Text) = 4 then
SelectNext(Edit, True, True);
end;
procedure TForm1.EditEnter(Sender: TObject);
var
Edit: TEdit absolute Sender;
begin
Edit.SelStart := Length(Edit.Text);
end;
procedure TForm1.EditExit(Sender: TObject);
var
Edit: TEdit absolute Sender;
begin
if not InRange(StrToIntDef(Edit.Text, -1), MinValue, MaxValue) then
Edit.SetFocus;
end;
procedure TForm1.EditKeyDown(Sender: TObject; var Key: Word;
Shift: TShiftState);
var
Edit: TEdit absolute Sender;
begin
if (Edit <> Edit1) and (Length(Edit.Text) = 0) and (Key = VK_BACK) then
begin
Edit.OnExit := nil;
SelectNext(Edit, False, True);
Edit.OnExit := EditExit;
end;
end;
You also might set the NumbersOnly
property to True which will cause a Windows warning balloon when someone tries to enter an alphabetic character.
Reflection
Validating every Edit seperately in OnExit
will cause trouble for the user. When the user wants or desides to abort the operation, for whatever reason, he is not able to because the cancel button cannot be reached untill he enters a valid number. Another example situation would be entering second value partially, and wanting to return to the previous for correction.
Do not harass users with such inconvenience. Instead, validate all values afterwards. Intermediate invalidation could be visually signalled by using colors, stars, exclamation marks, icons, etc...