Delphi:FormStyle:fsStayOnTop。InputQuery在线程中并且在一个窗体后面。

3
如何解决?FormStyle:fsStayOnTop。我在线程中调用输入查询,但它出现在主窗体后面或者不可见!我在线程中动态创建ZipForge。
procedure StartUpdating.DoPassword;
var
  S: String;
begin
  if PassSkip then
    FSkipFile := True
  else if InputQuery('Pas', FFileName, S) then
    FPassword := AnsiString(S)
  else
  begin
    PassSkip := True;
    FSkipFile := True;
    Terminate;
  end;
end;
procedure StartUpdating.ZipForgePassword(Sender: TObject; FileName: String;
  var NewPassword: AnsiString; var SkipFile: Boolean);
begin
  FFileName := FileName;
  FPassword := NewPassword;
  FSkipFile := SkipFile;
  Synchronize(DoPassword);
  FileName := FFileName;
  NewPassword := FPassword;
  SkipFile := FSkipFile;
end;

即使我从线程中调用它,也无法帮助我:
Function TForm1.InQuery(cap1: string; cap2: string):bool;
var s:string;
begin
  if InputQuery(cap1,cap2,s) then
  begin
  ThreadUpdating.MainPas:=s;
  result:=true;
  end else result:=false;
end;

这不是一个问题。您需要提供更多信息并发布一些实际的代码。按照您目前的描述,无法回答该问题。 - Ken White
我这样做,但如果表单不是fsStayOnTop,一切都没问题。 - maxfax
我不确定,可能InputQuery是隐藏的。 - maxfax
2
他正在从一个 fsStayOnTop 表单中调用 InputQuery,但是 InputQuery 对话框现在在他的表单后面。 - Ian Boyd
@Ian:太好了。请提供一个解决方案。 - Ken White
@Ken White:我只是帮忙澄清对这个问题的困惑。 - Ian Boyd
1个回答

3

编辑(2)

InputQuery() 显示的表单是一个模态窗体(使用 .ShowModal 显示),Delphi 的 VCL 足够智能,确保没有模态窗体显示在最上面的窗口后面。实质上,调用了 DisableTaskWindowsNormalizeAllTopMosts,其中有趣的是 NormalizeAllTopMosts: 这确保了在显示模态窗体时没有最上层窗口。这些调用不是直接进行的,VCL 使用了许多技巧来实现这一点。可以通过阅读 TCustomForm.ShowModalForms.DisableTaskWindowsTApplication.WndProc 的代码(特别是处理 WM_ENABLE 消息的方式)来了解详细信息。

需要知道的是,似乎存在一个 bug,允许模态窗体在应用程序的主窗体后面显示,如果主窗体是最上层的。这在 Delphi 2010 和 Delphi XE 上都发生了,没有在旧版本中测试。测试非常简单:创建一个新的 Delphi VCL 应用程序,在 Form1 上设置 FormStyle=fsStayOnTop,放置一个按钮,在按钮的 OnClick 中执行以下操作:

procedure TForm2.Button1Click(Sender: TObject);
var s:string;
begin
  s := '';
  InputQuery('a', 'b', s);
end;

修复方法

这应该被视为一个临时解决方案,因为显然设计要求在显示模态窗体之前将最上层窗口“降级”。如果您知道您的主窗体是最上层的,则在调用任何ShowModal之前应执行以下操作:

MainForm.FormStyle := fsNormal;
try
  YourDialog.ShowModal;
finally MainForm.FormStyle := fsStayOnTop;
end;

对于InputQuery的特定情况,可以使用类似以下函数的函数。请注意,我包含了将文本编辑器转换为密码编辑器的功能,这是基于OP在另一个问题中的要求:

function CustomInputQuery(const Caption, Prompt: string; const Password:Boolean; var Value:string): Boolean;
var F: TForm;
    Ed: TEdit;
    Lb: TLabel;
    Bt: TButton;
    WasStayOnTop:Boolean;
begin
  F := TForm.Create(nil);
  try
    F.Caption := Caption;

    Lb := TLabel.Create(F);
    Lb.Parent := F;
    Lb.Caption := Prompt;
    Lb.Left := 8;
    Lb.Top := 8;

    Ed := TEdit.Create(F);
    Ed.Parent := F;
    Ed.Left := Lb.Left + Lb.Width + 8;
    Ed.Top := 8;
    Ed.Width := 150;
    Ed.Text := Value;
    if Password then
      Ed.PasswordChar := '*';

    Bt := TButton.Create(F);
    Bt.Caption := 'Ok';
    Bt.Default := True;
    Bt.ModalResult := mrOk;
    Bt.Left := 8;
    Bt.Top := Ed.Top + Ed.Height + 8;
    Bt.Parent := F;

    Bt := TButton.Create(F);
    Bt.Caption := 'Cancel';
    Bt.Cancel := True;
    Bt.ModalResult := mrCancel;
    Bt.Left := 8 + Bt.Width + 8;
    Bt.Top := Ed.Top + Ed.Height + 8;
    Bt.Parent := F;

    F.Width := F.Width - F.ClientWidth + Ed.Left + Ed.Width + 8;
    F.Height := F.Height - F.ClientHeight + Bt.Top + Bt.Height + 8;
    F.Position := poDesktopCenter;

    WasStayOnTop := Assigned(Application.MainForm) and (Application.MainForm.FormStyle = fsStayOnTop);
    if WasStayOnTop then Application.MainForm.FormStyle := fsNormal;
    try
      if F.ShowModal = mrOk then
        begin
          Value := Ed.Text;
          Result := True;
        end
      else
        Result := False;
    finally if WasStayOnTop then Application.MainForm.FormStyle := fsStayOnTop;
    end;

  finally F.Free;
  end;
end;

我只有主菜单->设置窗口置顶。fsStayOnTop + F.ShowModal都存在,但它不起作用。 - maxfax
N8.Checked := not N8.Checked; 如果 N8.Checked=true 则 Form1.FormStyle:=fsStayOnTop 否则 Form1.FormStyle:=fsNormal。就是这样。 - maxfax
1
你的第一个段落是错误的。InputQuery 是以模态方式显示的,而在模态状态下所有任务窗口都被禁用。禁用应用程序窗口正是出于这个原因调用了 NormalizeAllTopMosts。尝试使用 D2007 之外的版本,你会发现输入窗体将位于“始终置顶”窗体上方... - Sertac Akyuz
@Sertac,这与主窗口是最顶层窗口有关。我进行了另一个测试,在该测试中,主窗口不是最顶层窗口,而是有另一个最顶层窗口,模态窗体如预期地显示在最顶层窗口上方。我不确定规范化是否出现问题,因为将应用程序的主窗口置于最顶层并没有太多意义。 - Cosmin Prund
@Cosmin - 一个最顶层的主窗口应该保持在其他应用程序窗口的顶部,这可能不是一个体贴的设计,但它可能有一个目的。关于添加答案,我可以建议使用“弹出模式”,但由于没有最近的版本,我不太确定详细情况。 - Sertac Akyuz
显示剩余11条评论

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