【问题标题】:Occasional stuck splash screen (win 7 embedded)偶尔卡住闪屏(win 7嵌入式)
【发布时间】:2017-07-10 04:24:21
【问题描述】:

我有一个在启动时恢复窗口的应用程序,但这会在创建和定位每个窗口时导致潜在的闪烁。

为了解决这个问题,我将初始屏幕(拉伸到屏幕的全尺寸)设置为“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;

马丁

【问题讨论】:

  • 您是否尝试使用简单的 TTimer 而不是 TTask?您是否尝试评论 FreeAndNil(fSplash) 并检查这是否改变了什么?

标签: delphi vcl delphi-10.1-berlin


【解决方案1】:

您不需要递归地使所有内容无效,只需使表单本身无效就足够了。

如果您升级到 10.2 Tokyo,您现在可以在 TTask 中使用 TThread.ForceQueue() 而不是 TThread.Synchronize():

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;

【讨论】:

  • ForceQueue 对我来说是一个新的。我会查一下,但由于移动开发的错误,我还没有搬到东京。我不确定为什么 Queue 在这种情况下应该有所不同,但值得一试。
  • Timer 的想法可能是最好的想法,尽管在代码方面不太优雅。
猜你喜欢
  • 2019-01-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-12-02
  • 1970-01-01
  • 2018-10-12
相关资源
最近更新 更多