Delphi:在FormShow中重绘表单

时间:2015-07-21 23:26:59

标签: delphi delphi-xe7

我在FormMain中打开Form2.ShowModal。我希望应用程序在执行某些数据库访问时显示Form2(这与要显示的新数据无关)。但是,在执行FormShow时,只显示外边框和一些损坏的部分,FormMain的一些损坏部分显示出来。这太丑了。

我无法找到一种方法让Delphi立即重新绘制Form,然后执行耗时的MyOpenData过程。在总结MyOpenData之后,一切都很好。

procedure TForm2.FormShow(Sender: TObject);
begin
  Invalidate; 
  Refresh;
  MyOpenData; { needs some seconds of database accesses }
end;

替代:

procedure TForm2.FormShow(Sender: TObject);
begin
  Invalidate;
  Refresh;
  SendMessage(Handle, wm_paint, 0, 0);
  PostMessage(Handle, wm_OpenMyData, 0, 0); { executes well, but no solution)
end;

这也不起作用。我以为SendMessage()等待消息完成。但是在MyOpenData之前没有完成Paint。在程序结束之前,表单总是看起来很破碎。除此之外,例程执行得很好。我组合或单独尝试了所有这些命令。

我错过了什么?提前谢谢!

如何启动需要在打开表单时运行的耗时例程?

(Windows 7 64位上的Delphi XE7)

3 个答案:

答案 0 :(得分:-1)

uses
WinApi.Windows;

const
WM_AFTER_SHOW     = WM_USER + 1; // custom message
WM_AFTER_CREATE   = WM_USER + 2; // custom message

private

procedure WmAfterCreate(var Msg: TMessage); message WM_AFTER_CREATE;
procedure WmAfterShow(var Msg: TMessage); message WM_AFTER_SHOW;


procedure TForm1.WmAfterCreate(var Msg: TMessage);
begin
 DoSomeThingAfterCreate();
 ShowMessage('WM_AFTER_CREATE received!');
end;

procedure TForm1.WmAfterShow(var Msg: TMessage);
begin
  DoSomeThingAfterShow();
  ShowMessage('WM_AFTER_SHOW received!');
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
 // Some code...
PostMessage(Self.Handle, WM_AFTER_CREATE, 0, 0);
end;

procedure TForm1.FormShow(Sender: TObject);
begin
 // Some Code...
 PostMessage(Self.Handle, WM_AFTER_SHOW, 0, 0);
end;

答案 1 :(得分:-2)

目前没有足够的信息来提出任何具体的建议,IMO。

我猜测MyOpenData()会设置Form2所依赖的某种数据状态。如果是这种情况,那么您可能希望在调用Form2.ShowModal之前调用它。在任何情况下,您都不应该在OnShow处理程序内调用invalidate或refresh,因为它们都会触发OnShow。

观看我为CodeRage 9制作的视频,"你最近拥抱过你的软件管道工吗?" (在YouTube上搜索'编码软件管道工')因为这是我在此视频中解决的确切主题 - 初始化表单和对象所涉及的大量问题,以及特定的时间问题形式。

我没有具体讨论数据感知控件的问题,但它们几乎完全相同。从依赖于该状态的表单内部设置DB状态以便正确初始化自身可能会有问题。通过首先进行依赖初始化,然后将该依赖项注入表单,可以轻松避免固有的竞争条件。

如果涉及DB,则必须将SOMETHING注入表单:DB引用(通常通过全局变量);表(全局变量或表单变量);或当前记录(通常是表单变量)。使用DB-aware控件的好处是初始化总是隐含的,你不必注入任何东西。使用DB-aware控件的不好的部分是,初始化总是隐式的,并且您没有对初始化序列的EXPLICIT控制。通过对数据库依赖关系进行EXPLICIT注入,可以解决时间问题。这项工作多一点(不多),但你不必处理这样的事情。

在任何情况下,如果表单需要当前记录来初始化其字段,则您无法显示表单,直到选择了记录,并且您无法将记录选择部分作为表单和&n #39;初始化过程没有冒并发问题的风险。它可以做到,但是你可以把它弄得一团糟。

答案 2 :(得分:-3)

这应该有效。

  • 在表单上放置一个计时器,并在Object Inspector中将Enabled设置为False。
  • 在FormCreate中设置为Enabled为True
  • 在OnTimer事件中输入您的代码。

您必须猜测间隔值。如果FormCreate中没有很多组件或很多代码,那么几百毫秒就足够了。否则放入有效的工作 - 500或甚至1000毫秒。