En realidad la forma que a la larga termina siendo la mas sencilla y clara es que encapsules todo ese comportamiento en una clase
Por ejemplo, algo super sencillo
Código Delphi
[-]
TPago = class
private
FEfectivo: currency;
FCheque: currency;
FDirty: boolean;
procedure SetEfectivo(const Value: currency);
procedure SetCheque(const Value: currency);
function GetEfectivo: currency;
function GetCheque: currency;
function GetTotal: currency;
procedure Recalcular;
published
property Efectivo: currency read GetEfectivo write SetEfectivo;
property Cheque: currency read GetCheque write SetCheque;
property Total: currency read GetTotal;
end;
E implementar los getter y setter asi
Código Delphi
[-]
function TPago.GetEfectivo: currency;
begin
if (FDirty) then
Recalcular;
result := FEfectivo;
end;
procedure TPago.SetEfectivo(const Value: currency);
begin
if (Value <> FEfectivo) then
begin
FEfectivo := Value;
FDirty := true;
end;
end;
function TPago.GetTotal: currency;
begin
if (FDirty) then
Recalcular;
result := FEfectivo + FCheque;
end;
Aca el secreto esta en utilizar propiedades para obtener y acceder a los valores, en el atributo FDirty (Sucio) y el metodo Recalcular (todo esto es de un ejemplo que lei del viejo maestro Ian Marteens)
De esta manera nos aseguramos que cuando obtenemos un valor, este esta "actualizado" porque la clase sabe calcular el total. Imaginate si tenes que aplicar tasas de interes, impuestos, descuentos.. etc. Asi te quedaria todo el calculo del total en el metodo Recalcular (en un solo lugar) y podrias consultar y setear valores libremente sabiendo que siempre estaran ajustados dependiendo de los valores que setees.
Luego siguiendo la logica de lo que queres hacer, en el OnExit de los edit podrias validar que el importe efectivo es valido (por ejemplo) y mandarselo a la clase. La clase setea el valor y FDirty pasaria a True, por lo tanto la proxima lectura de algun valor llama a Recalcular y los montos son actualizados.
Entonces el OnExit de los edit quedaria
Código Delphi
[-]
procedure TForm1.Edit1Exit(Sender: TObject);
var Efvo: currency;
begin
try
Efvo := StrToCurr(Edit1.Text);
Pago.Efectivo := Efvo; Refrescar;
except
on EConvertError do
begin
Edit1.SetFocus;
MessageDlg('Importe inválido!', mtError, [mbOK], 0);
end;
end;
end;
Donde refrescar seria un proceso de tu form que se encarga de asignar a cada edit el valor correspondiente de la instancia de la clase Pago