Если вы спрашиваете, есть ли у VCL что-то вроде BeginInvoke в .NET из коробки, тогда ответ будет отрицательным. Однако вы можете получить нечто очень похожее в виде небольшого блока, который вы связываете с вашей программой, библиотеки AsyncCalls от Andreas Hausladen. Это не компонент, так что, я думаю, это подходит. Он также поддерживает Delphi начиная с версии 5. Очень рекомендуется.
Edit:
Я добавлю пример, так как вы не запустили его. Если вы получаете блокировку в своем вызывающем коде, то ваша проблема в том, что не сохраняется ссылка на указатель интерфейса IAsyncCall
, который вернула функция. Поэтому объект, реализующий интерфейс, будет немедленно уничтожен, когда временная ссылка выйдет из области видимости. Деструктор будет вызываться в контексте потока VCL и будет вызывать WaitForSingleObject()
или аналогичную функцию, ожидающую завершения рабочего потока. В результате ваш поток VCL блокируется.
Вы получите правильное поведение, если сохраните ссылку на указатель интерфейса:
type
TForm1 = class(TForm)
Button1: TButton;
Timer1: TTimer;
procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean);
procedure Button1Click(Sender: TObject);
procedure Timer1Timer(Sender: TObject);
private
fAsyncCall: IAsyncCall;
procedure WaitForIt(ADelay: integer);
end;
Установите таймер на отключенный и дайте ему очень короткий Interval
, скажем, 50 мс. Нажатие кнопки запускает асинхронную операцию:
procedure TForm1.Button1Click(Sender: TObject);
begin
Button1.Enabled := FALSE;
fAsyncCall := AsyncCall(WaitForIt, 1000);
end;
procedure TForm1.WaitForIt(ADelay: integer);
begin
Sleep(ADelay);
EnterMainThread;
try
Randomize;
Color := RGB(Random(256), Random(256), Random(256));
Timer1.Enabled := TRUE;
finally
LeaveMainThread;
end;
end;
Пока операция активна, запуск других операций невозможен. По завершении он позволяет таймеру уведомить форму и сбросить ссылку на интерфейс:
procedure TForm1.Timer1Timer(Sender: TObject);
begin
Timer1.Enabled := FALSE;
Assert((fAsyncCall <> nil) and fAsyncCall.Finished);
fAsyncCall := nil;
Button1.Enabled := TRUE;
end;
procedure TForm1.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
begin
CanClose := (fAsyncCall = nil) or fAsyncCall.Finished;
end;
Обратите внимание, как можно получить доступ к форме напрямую из вызываемого метода, используя EnterMainThread()
и LeaveMainThread()
.
Выше код не является абсолютным минимумом, он предназначен только для демонстрации некоторых идей.