Случайный застрявший экран-заставка (встроенная победа 7)
У меня есть приложение, которое восстанавливает окна при запуске, но это приводит к потенциальному мерцанию, когда каждое окно создается и позиционируется.
Чтобы обойти это, я установил заставку (растянутую до полного размера экрана) на "StayOnTop" и закрыл ее после события OnShow, используя TTask. Проблема в том, что иногда заставка застревает. Если вы нажмете, где кнопки должны быть, они перерисовываются и отображаются правильно. Я пытался "аннулировать" все WinControls, но эта проблема все еще появляется. Я никогда не видел проблемы в отладчике.
Есть ли еще какие-нибудь хитрости, которые кто-либо может предложить для принудительной полной перекраски экрана?
Вот мой код для закрытия всплеска - это в OnShow основной формы.
aTask := TTask.Create(procedure()
begin
Sleep(800);
TThread.Synchronize(nil, procedure()
begin
fSplash.Close;
FreeAndNil(fSplash);
DoInvalidate(self);
end);
end);
aTask.Start;
Вот моя попытка все сделать недействительной...
Procedure DoInvalidate( aWinControl: TWInControl );
var
i: Integer;
ctrl: TControl;
begin
for i:= 0 to aWinControl.Controlcount-1 do
begin
ctrl:= aWinControl.Controls[i];
if ctrl Is TWinControl then
DoInvalidate( TWincontrol( ctrl ));
end;
aWinControl.Invalidate;
end;
Мартин
1 ответ
Вам не нужно рекурсивно аннулировать все, достаточно просто аннулировать саму форму.
Если вы обновитесь до 10.2 Токио, теперь вы можете использовать TThread.ForceQueue()
вместо TThread.Synchronize()
в TTask
:
procedure TMainForm.FormShow(Sender: TObject);
begin
TThread.ForceQueue(nil, procedure
begin
FreeAndNil(fSplash);
Application.MainForm.Invalidate;
end
);
end;
Если вы придерживаетесь TTask
, ты должен хотя бы использовать TThread.Queue()
вместо:
procedure TMainForm.FormShow(Sender: TObject);
begin
TTask.Create(procedure
begin
TThread.Queue(nil, procedure
begin
FreeAndNil(fSplash);
Application.MainForm.Invalidate;
end;
end
).Start;
end;
Или вы можете просто использовать короткий TTimer
, как предложил zdzichs:
procedure TMainForm.FormShow(Sender: TObject);
begin
Timer1.Enabled := True;
end;
procedure TMainForm.Timer1Timer(Sender: TObject);
begin
Timer1.Enabled := False;
FreeAndNil(fSplash);
Invalidate;
end;
Или вы можете назначить OnClose
обработчик события в форме всплеска, чтобы сделать недействительной MainForm, а затем PostMessage()
WM_CLOSE
сообщение в виде заставки:
procedure TMainForm.FormCreate(Sender: TObject);
begin
fSplash := TSplashForm.Create(nil);
fSplash.OnClose := SplashClosed;
fSplash.Show;
end;
procedure TMainForm.FormShow(Sender: TObject);
begin
if fSplash <> nil then
PostMessage(fSplash.Handle, WM_CLOSE, 0, 0);
end;
procedure TMainForm.SplashClosed(Sender: TObject; var Action: TCloseAction);
begin
fSplash := nil;
Action := caFree;
Invalidate;
end;
Или используйте OnDestroy
событие вместо:
procedure TMainForm.FormCreate(Sender: TObject);
begin
fSplash := TSplashForm.Create(nil);
fSplash.OnDestroy := SplashDestroyed;
fSplash.Show;
end;
procedure TMainForm.FormShow(Sender: TObject);
begin
if fSplash <> nil then
fSplash.Release; // <-- delayed free
end;
procedure TMainForm.SplashDestroyed(Sender: TObject);
begin
fSplash := nil;
Invalidate;
end;