1

I have 7 edits where the user can put numbers,the numbers must be between 1100 and 1500. At the beginning, the first edit is focused, and the the user enter his number, and then he push tab to focus to the next edit...

My program must verify the number that was entred by the user and if it dont satisfy the condition (1100

I tried this code on the Edit1Change but it won't work

If (1500 < (strtofloat(edit1.text)) or (strtofloat(edit1.text) <1100) then
begin
  Showmessage ('my message');
  edit1.setfocus
end;

Update

Excuse me guys, my description for the problem wasn't very clear, and my english is not very good as well.

I don't have problem with the comparison or checking the condition, my problem is that when I select the next Edit by pressing TAB, even if the condition wasn't satisified, my message appears, Edit1.Text is reset to 0 and the cursor moves to the next Edit control. What I want is that when the user presses Tab and the number entred doesn't satisfy the condition, the message appears, Edit1.Text takes 0 and the cursor stays on Edit1.

I tried to place the checking of the condition and the instruction to give focus to the same edit in Edit1.OnExit but it won't work as well, always when the user presses Tab after entering a number that doesn't satisfy the condition, the message appears, the first Edit takes 0 and the cursor moves to the next Edit.

NGLN
  • 43,011
  • 8
  • 105
  • 200
user2931832
  • 11
  • 1
  • 1
  • 2
  • 1) what do you mean by "does not work" ? 2) you may use any ready-made component to enter numbers that already has checks for min and max 3) you may use any ready-made library that validates input and mark wrong entries – Arioch 'The Oct 29 '13 at 11:47
  • Couldn't agree more. Why do you rely on TEdits when there are TSpinEdits and the like? Also, the `OnChange` event is not suitable for that because it doesn't fire when the user leaves the edit component by mouseclick or Tab. – Günther the Beautiful Oct 29 '13 at 11:52
  • 2
    @GünthertheBeautiful there is also problem with solely using OnExit: it does not work when the dialog is closed by ENTER or ESC key - when the focus is not actally passed further but just the form is closed. Or when TPageControl tabs is switched or maybe dialog closed by click on TSpeedButton or TMenuItem - the event cannot set focus back, because TEdit.Parent is already invisible. So one should better rely on some form-wide validation framework – Arioch 'The Oct 29 '13 at 11:59
  • @user29 : My Answer how to catch a `tab` key pressed. [Event for tab](http://stackoverflow.com/a/16888843/1322642) – moskito-x Oct 29 '13 at 18:08
  • Thank you , The link for Event for tab helped me so much, the solution was to place the checking for the condition and the instruction (edit1.setfocus), on the Key up Of the next edit ;) – user2931832 Oct 30 '13 at 09:20
  • I cannot reproduce this. _Edit1.Text is reset to 0_: then that's due to other code. We need to see áll code, because you're doing something that you haven't told us. – NGLN Oct 30 '13 at 17:21
  • @user2931832 : Glad that my answer could help you. `KeyUp Event of the following TEdit` . To show other readers you got it, you should accept an answer. – moskito-x Apr 26 '14 at 12:55
  • Note that SetFocus cannot be use directly. You need to call firs CanFocus. But even that will not work in all cases. CanFocus is **BROKEN** (or incomplete in Delphi). Please check this article on how to [fix it](https://gabrielmoraru.com/setfocus-is-broken-in-delphi/) – Gabriel Mar 29 '23 at 14:11

4 Answers4

3

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...

NGLN
  • 43,011
  • 8
  • 105
  • 200
1

Navigation keys (Tab, BackTab, the arrow keys, and so on) are unaffected by KeyPreview because they do not generate keyboard events.
The only place which points to this fact. Delphi Help TCustomForm.KeyPreview

The only event you can use is the KeyUp Event of the following or previous TEdit.

Look here for an example : Answer to Intercept TAB key in KeyPress event

Community
  • 1
  • 1
moskito-x
  • 11,832
  • 5
  • 47
  • 60
0

then he push tab to focus to the next edit

That is intercepted by OnExit event http://docwiki.embarcadero.com/Libraries/XE2/en/Vcl.Controls.TWinControl.OnExit

tried this code on the Edit1Change but it won't work

What do you mean by "does not work" ?

It actually works - it continually sets focus to the edit you are keying text into. However that is bad time to check for changes: when user "1100" to "1500" user most probably have intermediate result of "100" or "15100" where your application would crash his work by modal dialogs.

You should either avoid checking while editing and only check after edit made. Or you should display result of the check in a non-interfering non-modal way, so the user would continue editing. Like changing TEdit's background between red and green or like using some validators library to add error marks.

Or just use the numeric editor with those min, max and checks built-in

Mogsdad
  • 44,709
  • 21
  • 151
  • 275
Arioch 'The
  • 15,799
  • 35
  • 62
-1

It's an old question but as i can't see the right answer:

Never manipulate focus meanwhile the focus is changing. In OnExit windows started to move the focus but didn't finished yet. If you want to interrupt the focus change because of validation, use "Abort;"

procedure Txy.OnExit()
begin
 if not Validate then
   Abort;
end;

Also make sure that you are not manipulating the focus in the OnClose event because it will eventually trigger an unwanted OnExit of the active control.

Atys
  • 109
  • 6