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;
精彩评论