He elaborado un ejemplo que creo que se aproxima bastante a lo que quieres, esto se basa en 3 arrays (para este ejemplo de 4 elementos), uno de TWinControl, en el que vamos a colocar los controles que necesitan de validación, en donde la propiedad Tag de cada elemento corresponde al índice en el array (se hubiera podido hacer en la propiedad TabOrder, pero cuando hay controles anidados en grupos, páginas, etc la cosa podría complicarse, por eso he optado por el TAG; un segundo array de Boolean, en el que se colocarán las condiciones a evaluar para cada control del array de controles, en el que, como es lógico, los índices deben corresponder con los dos arrays; y un tercer array de string con los mensajes a mostrar en caso de que que no se cumplan las condiciones del array de Boolean, los índices deben corresponder con los de los otros dos arrays. Ademas agregamos un campo privado de tipo entero FTagUltimoControl en el que guardaremos el Tag del último control.
Al crear el Form inicializamos los array de Controles y de Mensajes así como el valor del campo FTagUltimoControl.
Compartimos el procedimiento ControlarEntradas en el evento OnEnter de los controles que hacen parte del array de controles. En este procedimiento comparamos el valor del Tag del control que recibe el foco contra el valor del Tag del control anterior almacenado en el campo FTagUltimoControl, solo si el Tag es mayor al anterior se dispara la validación del control anterior almacenada en el array de Condiciones en el caso contrario no pasa nada (que es lo que tu quieres si el usuario "se devuelve").
Compartimos el procedimiento ControlarSalidas en el evento OnExit de los controles que hacen parte del array de controles. En este procedimiento actualizamos el valor de FTagUltimoControl con el valor del Tag del control que pierde el foco y pasamos el valor booleano de la posible validación, para que sean usados si es necesario en el evento OnEnter del control que recibe el foco.
Debes evitar colocar validaciones individuales en el evento OnExit de los controles, pues estas deben colocarse en el array de condiciones, de lo contrario siempre que salgas del control se ejecutaría.
Finalmente en el evento OnClick del botón, simplemente pasamos los valores a validar, recorremos el array de Condiciones y hacemos todas las validaciones de menor a mayor, devolviendo el foco al control que no cumpla y enviando el respectivo mensaje de error.
He puesto una función complementaria (ESNumero) para evitar el error de tipo al evaluar la condición del Edit3 del ejemplo, esta no es relevante, en caso de que lo que que estés validadndo campos de un Dataset es más fácil validar en función de los valores del campo en cuestión.
Espero te sirva de guía para implementar lo que quieres.
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;
type
TForm1 = class(TForm)
Edit1: TEdit;
Edit2: TEdit;
Edit3: TEdit;
Edit4: TEdit;
Button1: TButton;
procedure FormCreate(Sender: TObject);
procedure ControlarEntrada(Sender: TObject);
procedure ControlarSalida(Sender: TObject);
procedure Button1Click(Sender: TObject);
private
FControles: array [1 .. 4] of TWinControl;
FCondiciones: array [1 .. 4] of Boolean;
FMensajes: array [1 .. 4] of string;
FTagControlAnterior: Integer;
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.FormCreate(Sender: TObject);
begin
// Inicializo controles
FControles[1] := Edit1;
FControles[2] := Edit2;
FControles[3] := Edit3;
FControles[4] := Edit4;
// Inicializo mensajes
FMensajes[1] := 'Edit1 debe contener un valor';
FMensajes[2] := 'El número de carcateres de Edit2 debe ser maypor que 3';
FMensajes[3] := 'El valor de Edit3 debe ser mayor que 7';
FMensajes[4] := 'El valor de Edtit4 debe ser diferente de hola';
// Inicializo Control
FTagControlAnterior := 1
end;
procedure TForm1.ControlarEntrada(Sender: TObject);
begin
if TWinControl(Sender).Tag > FTagControlAnterior then
if not FCondiciones[FTagControlAnterior] then
begin
ShowMessage(FMensajes[FTagControlAnterior]);
FControles[FTagControlAnterior].SetFocus;
end;
end;
function EsNumero(const S: string): Boolean;
var
k: Integer;
begin
Result := False;
if length(Trim(S)) > 0 then
begin
for k := 1 to length(Trim(S)) do
case Trim(S)[k] of
'0' .. '9':
;
else
Exit;
end;
Result := True;
end;
end;
procedure TForm1.ControlarSalida(Sender: TObject);
begin
FTagControlAnterior := TWinControl(Sender).Tag;
case TWinControl(Sender).Tag of
1:
FCondiciones[1] := Edit1.Text <> '';
2:
FCondiciones[2] := length(Edit2.Text) > 3;
3:
FCondiciones[3] := EsNumero(Edit3.Text) and (StrToInt(Edit3.Text) > 7);
4:
FCondiciones[4] := Edit4.Text <> 'Hola';
end;
end;
procedure TForm1.Button1Click(Sender: TObject);
var
K: Integer;
begin
FCondiciones[1] := Edit1.Text <> '';
FCondiciones[2] := length(Edit2.Text) > 3;
FCondiciones[3] := EsNumero(Edit3.Text) and (StrToInt(Edit3.Text) > 7);
FCondiciones[4] := Edit4.Text <> 'Hola';
for K := low(FCondiciones) to High(FCondiciones) do
if not FCondiciones[K] then
begin
ShowMessage(FMensajes[K]);
FControles[K].SetFocus;
Exit;
end;
end;
end.