如何在模态表单处于活动状态时重新绘制父表单?

时间:2008-11-13 23:55:04

标签: delphi

在Delphi 2006中,我正在展示一种模态形式。该表单中的用户输入可以更改当前可能显示在作为主窗体的父窗体上的数据。为了反映这些变化,我需要在主窗体上强制重绘一些所有者绘制的组件。我尝试从模态形式这样做:

MainForm := Application.MainForm;
MainForm.Invalidate;
MainForm.Update;

这没有改变一点。我一直以为表格上的“更新”总是会立刻重新绘制 - 显然不是这样。绘画代码本身应该没问题,因为我可以将模态形式移动到那些ownerdraw组件上以强制手动重绘。

但是,如何在数据更改时以编程方式强制重绘?

编辑:我将在下周尝试Application.ProcessMessages和Refresh,感谢您的建议。

很抱歉花了这么长时间才回答并感谢所有回复的人。调用Refresh()是解决方案的一部分,但必须在自定义绘制组件上完成,而不是在他们所使用的表单上...现在我想接受多个答案; - )

6 个答案:

答案 0 :(得分:3)

也许值得一提的是,如果你使用的皮肤库也可以影响它。我发现我必须刷新皮肤库,而不是表单。

答案 1 :(得分:1)

更新发送WM_PAINT消息。 Refresh通过执行绘制消息强制重新绘制控件。尝试改为.Refresh。

答案 2 :(得分:1)

模态表单上的编辑是否直接写入父表单上的控件?如果是,那么他们应该自动更新。

当您在其上移动模态窗体时,父窗体是否会形成“白色”(即一起停止绘画)?如果是这样,那么你调用模态表单的方式还是有其他问题,或者如Kluge建议的那样,你阻止发送消息(甚至可能是一个线程问题。)

我测试了这个,它默认工作。您需要两个表单,一个带有编辑框,另一个带有按钮。然后分配这些事件处理程序:

procedure TForm1.Button1Click(Sender: TObject);
begin
  Form2.ShowModal;
end;

procedure TForm2.Edit1Change(Sender: TObject);
begin
  Form1.Button1.Caption := Edit1.Text;
end;

当您在第二个表单上更改Edit1时,它将更改Form1上按钮的标题。

答案 3 :(得分:1)

尝试以下代码。只需将此代码段插入您自己的代码中,然后随时随地调用它(但可能不是来自某个线程,如果没有同步,可能会变得混乱)。它会在应用程序中绘制所有窗口,而不依赖于消息循环来执行此操作。

procedure UpdateApplication;
// Updates (repaints where nesc) all windows of the app
  function UpdateWindow(hWnd: HWND; LParam: longint): bool; stdcall;
  begin
    Result := True;
    Windows.UpdateWindow(hWnd);
  end;
begin
  EnumWindows(@UpdateWindow, 0);
end;

答案 4 :(得分:0)

您是否有可能在子表单中执行某些操作来阻止邮件?是否添加:

Application.ProcessMessages;

你的代码会有什么不同吗?

答案 5 :(得分:0)

我猜你的模态形式可能会阻止消息。如果你处于某种循环中,那么尝试使用进度更新mainform进行某种处理。 Application.ProcessMessages是获取这些消息的一种方式,但不是很优雅。当我之前遇到过这种类型的问题时,我已经在Application.OnIdle事件中实现了处理。基本上,您需要做的是将处理分成小块。所以假设你正在处理一些循环。将循环的一次迭代作为任务的一个块。将该代码放在具有以下签名的方法中:

procedure DoIdle(Sender: TObject; var Done: Boolean);

确保Done设置为False。如果您的代码以前是:

for i := 1 to ProcessCount do
  DoProcess(i);

然后变成:

procedure MyDoIdle(Sender: TObject; var Done: Boolean);
begin
  Inc(TaskCount);
  If TaskCount <= ProcessCount then
    DoProcess(TaskCount);
end;

并按如下方式进行设置:

TaskCount := 0;
Application.Idle := MyDoIdle;

每当Application处于空闲状态时,代码就会运行,并且正常处理消息循环。记得在完成后将Application.OnIdle设置为nil。

如果DoProcess有点太快,你可以选择每次调用onidle做5或10次迭代。