Случайный застрявший экран-заставка (встроенная победа 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;
Другие вопросы по тегам