Witam,
Mam być może banalny problem, a może nie. Otóż, mój program (pomocnik w kompilacji źródeł) wykonuje wiele różnych operacji, czasami wymagających. Na formie wyświetlam całkowity czas działania różnych operacji, który odświeżany jest w czasie rzeczywistym (a program po prostu zbiera informacje z różnych plików tworząc nowe, w pętlach, często zagnieżdżonych, odpala kompilację podprogramów Delphi (w linii komend, przy użyciu MSBuild), odpala zewnętrzny kompilator (NSIS, tworzy instalator) i różne takie bzdety).
Do tak prostej operacji jak wyświetlanie czasu używam standardowych komponentów, TTimer oraz TLabel. Ale, jest tutaj PROBLEM - jeśli program wykonuje jakieś bardziej wymagające operacje (wystarczy pętla po wielu elementach) czas nie odświeża się. Zajęty główny wątek programu uniemożliwia działanie timera.
procedure TMainFrm.TimerTimer(Sender: TObject);
begin
MainFrm.Lbl_StopTime.Caption := TimeTostr(Now);
end;
Teoretycznie może pomóc instrukcja Application.ProcessMessages. Ale, niestety - to też nie pomaga.
Jakie jest rozwiązanie tego wydawałoby się banalnego problemu? Z pewnością czegoś nie wiem.
Szukając informacji znalazłem ciekawe rozwiązanie z osobnym wątkiem i odpalaniem zdarzenia, coś takiego (powinno działać, ale nie działa!):
type
TTimerThread = class(TThread)
private
FTickEvent: THandle;
procedure ProcessGUI;
protected
procedure Execute; override;
public
constructor Create(CreateSuspended: Boolean);
destructor Destroy; override;
procedure FinishThreadExecution;
end;
type
TMainFrm = class(TForm)
private
{ Private declarations }
FTimerThread: TTimerThread;
public
{ Public declarations }
end;
//...
procedure TMainFrm.FormCreate(Sender: TObject);
begin
FTimerThread := TTimerThread.Create(False);
end;
procedure TMainFrm.FormDestroy(Sender: TObject);
begin
FTimerThread.FinishThreadExecution;
end;
{ TTimerThread }
constructor TTimerThread.Create(CreateSuspended: Boolean);
begin
inherited;
FreeOnTerminate := True;
FTickEvent := CreateEvent(nil, True, False, nil);
end;
destructor TTimerThread.Destroy;
begin
CloseHandle(FTickEvent);
inherited;
end;
procedure TTimerThread.FinishThreadExecution;
begin
Terminate;
SetEvent(FTickEvent);
end;
procedure TTimerThread.Execute;
begin
while not Terminated do
begin
if WaitForSingleObject(FTickEvent, 100) = WAIT_TIMEOUT then
begin
Synchronize(ProcessGUI);
end;
end;
end;
procedure TTimerThread.ProcessGUI;
begin
Application.ProcessMessages;
MainFrm.Lbl_StopTime.Caption := TimeTostr(Now);
end;
Proszę o jakiś konstruktywny przykład rozwiązania tego problemu.
(Wyświetlenie czasu operacji, podczas np. dodawania 100 000 operacji w pętli, czy cokolwiek zajmującego główny wątek).
-Pawel