Delphi XE中主窗体和模态对话框的“Stay on top”功能

10
在Delphi XE Update 1中,如果父(主)窗体的FormStyle设置为fsStayOnTop,我会遇到似乎随机的模式窗体行为

1) 如果使用旧的MainFormOnTaskbar:= False方式,一切“只是工作”。 使用新的MainFormOnTaskbar:= True,则当主窗体设置为“置顶”时,模态窗体会被隐藏在主窗体后面。 在大多数情况下,建议说:

modalForm.PopupParent := self;

在调用modalForm.ShowModal之前添加Application.ProcessMessages似乎有帮助,但不总是有效。

2) 所有我的模态窗口都很简单,没有花哨的东西,位于MainFormCenter,不使用表单继承等。然而,PopupParent修复方法仅对其中约一半的窗口有效,而另一半窗口仍然会被主窗口遮挡。最奇怪的是,在某些情况下,无关代码行的排序会决定其是否有效。请参阅此代码中标记为(1)和(2)的行:

procedure TEchoMainForm.DBMaintenancePrompt( actions : TMaintenanceActions );
var
  frm : TDBMaintenanceForm;
begin
  frm := TDBMaintenanceForm.Create( self );
  try
    frm.Actions := actions; // (1)
    frm.PopupParent := self; // (2)
    frm.ShowModal;
  finally
    frm.Free;
  end;
end;

按照这个顺序执行时,模态表单会正确地显示在主要表单的上方。但是当我颠倒这些行时,模态表单会隐藏在主要表单后面。标记为(1)的行设置了模态表单的属性,导致TRzCheckGroup中的多个复选框被选中或取消选中,该TRzCheckGroup位于TRzPageControl上(Raize组件)。这是当上面的行(1)执行时运行的setter方法:

procedure TDBMaintenanceForm.SetActions(const Value: TMaintenanceActions);
var
  ma : TMaintenanceAction;
begin
  for ma := low( ma ) to high( ma ) do
    cgMaintActions.ItemChecked[ ord( ma )] := ( ma in Value );
  end;
end;

如果将代码中(1)和(2)的顺序颠倒,则足以使模态窗口在主窗口后面显示。

这可能与TRzCheckGroup有关(当setter代码运行时会对其进行操作),但我有另外两个遇到同样问题的窗体,并没有使用TRzCheckGroup(或TRzPageControl)。并且,我无法通过使用Raize组件的单独示例应用程序重现该问题。禁用表单、页面控件或TRzCheckGroup对setter的持续时间没有影响。

这似乎不是一个时间问题,因为一旦模态窗口显示隐藏,它就总是这样做。仅通过重新排列代码行来改变行为。

3) 最后一个观察结果:我的模态窗口相当简单,因此它们几乎可以立即显示,没有可见的延迟。但是当主窗口为fsStayOnTop时,很常见地看到模态窗口显示在其上方,然后被“推”到后面。然后,在按Esc键时,(看不见的)模态窗口会在主窗口顶部显示一小段时间,然后关闭。

我可能漏掉了某些明显的东西,或者这是一种召唤心理调试的方法,我不知道。请有什么想法吗?


更新。我尝试在另一个出现该问题的表单上跟踪问题。它有几个按钮(Raize)和一个TSyntaxMemo(来自eControl.ru的增强式备忘录组件)。这个表单与其他遇到问题的表单几乎没有任何共同点。经过删除部分代码并进行测试,我现在可以通过在将字符串分配给备忘录组件的方法中进行微小更改来重现该问题:

这是我的原始代码,它导致包含编辑器的窗体隐藏在主窗体后面:

procedure TEditorForm.SetAsText(const Value: string);
begin
  Editor.Text := Value;
end;
当我将赋值更改为空字符串时,表单会正确显示:
procedure TEditorForm.SetAsText(const Value: string);
begin
  Editor.Text := ''; // CRAZY! Problem goes away
end;

当我将一个单独的字符分配给编辑器时,表单开始再次隐藏:

procedure TEditorForm.SetAsText(const Value: string);
begin
  Editor.Text := 'a'; // Problem is back
end;

当然,另外两种有问题的形式并没有使用这个编辑器组件或它的任何单元。

我尝试删除备忘录控件并重新添加它(考虑创建顺序等等),但是没有效果。如果我在代码中创建备忘录也是一样的结果。只要将非空字符串分配给备忘录的Text属性,窗体就会隐藏。


我有点困惑。你说它按照它们的顺序使用编号行,但是那里的代码引用了Self,而不是对象实例的方法。发布的代码无法编译,更不用说工作了,无论行的顺序如何。当您不发布真正的代码时,很难解释代码异常。 :) - Ken White
@Ken:现在已经修复了,谢谢。这段代码是主窗体的一个方法,因此self引用是有效的。这是逐字逐句的代码。我在SetActions中简化了代码,但按照这里的写法编译后仍然会导致“隐藏”问题。 - Marek Jedliński
@moodforaday:你将模态窗体的PopupMode属性设置为什么了?你将TApplication.ModalPopupMode属性设置为什么了? - Remy Lebeau
@Remy:模态窗体的PopupMode是pmNone(默认值),但尝试使用pmAuto和pmExplicit没有效果。对于Application.ModalPopupMode也是如此。 - Marek Jedliński
在您进行编辑后,似乎应该开始跟踪TSyntaxMemo,特别是它的Text属性的setter,并查看它是否对焦点有任何影响。 - Ken White
@Ken:已经完成了。它将字符串分配给字符串列表,正如您所期望的那样。例如,没有消息处理。如果该值稍后被分配,例如在模态窗体的OnShow事件中,隐藏问题就会消失。不相关代码的微小更改对整个表单的行为产生了蝴蝶效应。很难想象* Raize控件和SyntaxMemo通过它们执行的某些操作会导致相同的问题。 - Marek Jedliński
2个回答

0

我之前也遇到过同样的问题。我的解决方案是在模态窗体的OnShow事件中添加Self.BringToFront;


-1

Windows不支持许多应用程序的最顶层窗体。而模态窗体默认是最顶层的。但你可以为自己的窗体设置这种样式。

有一个决定:移除主窗体的最顶层属性(没有可见效果),调用模态窗体,在模态窗体完成后重新设置最顶层样式。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接