perchè il refresh della gui è ottimizzato e viene disegnato tutto insieme, non dopo ogni singola istruzione
per disottimizzarlo (passami il termine :D ) puoi forzare l'esecuzione della coda dei messaggi della tua applicazione
prova:
edit1.text:='a';
Application.ProcessMessages;
sleep(1000);
edit1.text:='b';
Meglio ancora.....
crea una procedura di attesa non bloccante ne sui messaggi di sistema ne sui vari thread tipo questa:
Procedure Delay(MilliSecondi : Integer);
Var
Max : Integer;
Begin
Max := Integer(GetTickCount)+MilliSecondi;
Repeat
Application.ProcessMessages;
Until (Integer(GetTickCount) >= Max);
End;