开发者

Delphi: FormStyle:fsStayOnTop.InputQuery is in thread and BEHIND a Form

How to fix it? FormStyle:fsSt开发者_JAVA百科ayOnTop. I call Input Query in a thread, but it appears behind a main form or is not visible!

I dynamically create ZipForge in a thread.

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;

Even if I call this from a thread it does not help me:

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;


Edit (2)

The form shown by InputQuery() is a modal form (shown using .ShowModal, and Delphi's VCL is smart enough to make sure no modal form is shown behind a top-most window. Essentially calls are made to DisableTaskWindows and NormalizeAllTopMosts, the interesting one being NormalizeAllTopMosts: this makes sure there are no top-most windows while the modal form is shown. Those calls aren't directly made, the VCL uses a number of tricks to make it happen. The details can be found by reading the code for TCustomForm.ShowModal, Forms.DisableTaskWindows, TApplication.WndProc - specifically the handling of the WM_ENABLE message.

What needs to be known is that there appears to a bug allowing a modal form to be shown behind the Main form of the application, if the main form is top-most. This is happening on both Delphi 2010 and Delphi XE, didn't test with older versions. The test is very simple: Create a new Delphi VCL application, on Form1 set FormStyle=fsStayOnTop, drop a button and in the button's OnClick do this:

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

The fix

This should be considered a temporary fix, because clearly the design calls for top-most windows to be "degraded" before showing modal forms. If you know your main form is top-most, you should do something like this before calling ShowModal for anything:

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

In the particular case of InputQuery one can use a function similar to the following one. Please note I included the ability to turn the text editor into a password-editor, based on what the OP requested in an other question:

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;
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜