user2931832
user2931832

Reputation: 11

Set Focus back on edit after tab on Delphi xe2

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.

Upvotes: 1

Views: 20140

Answers (4)

Atys
Atys

Reputation: 132

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.

Upvotes: -1

Arioch &#39;The
Arioch &#39;The

Reputation: 16045

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

Upvotes: 0

moskito-x
moskito-x

Reputation: 11968

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

Upvotes: 1

NGLN
NGLN

Reputation: 43649

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

Upvotes: 3

Related Questions