在创建的表单上显示模态,无法访问模态表单
ShowModal on a created Form, no access to modal Form
我正在使用 David Heffernan 在这里分享的一款软件:
How can I allow a form to accept file dropping without handling Windows messages?
我已经将组件从 Form 更改为 Panel,这在 MainForm 中工作正常。
但是,在 ShowModal()
环境中使用时,我无法访问模态表单中组件的值。
我做了一个小demo来说明这个问题。
Unit1:
unit Unit1;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Vcl.ExtCtrls, Unit2;
type
TForm1 = class(TForm)
Button1: TButton;
procedure Button1Click(Sender: TObject);
private
protected
Public
End;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.Button1Click(Sender: TObject);
Var aForm: TForm2;
Begin
aForm := TForm2.Create(Nil);
Try
aForm.ShowModal;
Finally
aForm.Free;
End;
End;
End.
第 2 单元:
unit Unit2;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.ExtCtrls, Vcl.StdCtrls, DragAndDrop;
type
TmyPanel = class(TPanel, IDragDrop)
private
FDropTarget: TDropTarget;
// implement IDragDrop
function DropAllowed(const FileNames: array of string): Boolean;
procedure Drop(const FileNames: array of string);
protected
// procedure WMDropFiles(var Message: TWMDropFiles); message WM_DROPFILES;
procedure CreateWindowHandle(Const Params: TCreateParams); override;
procedure DestroyWindowHandle; override;
end;
TForm2 = class(TForm)
DropRefPanel: TPanel;
Label1: TLabel;
Button1: TButton;
procedure FormCreate(Sender: TObject);
procedure FormClose(Sender: TObject; var Action: TCloseAction);
procedure FormActivate(Sender: TObject);
procedure Button1Click(Sender: TObject);
{ Private declarations }
public
{ Public declarations }
DropPanel: TmyPanel;
end;
var
Form2: TForm2;
implementation
{$R *.dfm}
procedure TmyPanel.CreateWindowHandle(Const Params: TCreateParams);
begin
inherited;
FDropTarget := TDropTarget.Create(WindowHandle, Self);
end;
procedure TmyPanel.DestroyWindowHandle;
begin
FreeAndNil(FDropTarget);
inherited;
end;
function TmyPanel.DropAllowed(const FileNames: array of string): Boolean;
begin
Result := True;
end;
procedure TmyPanel.Drop(const FileNames: array of string);
Var i: Integer;
begin
// Form2.Label1.Caption := 'Drop';
begin
for i := 0 to Length(FileNames)-1 do
ShowMessage(Form2.Label1.Caption + ': ' + FileNames[i]);
end;
end;
procedure TForm2.Button1Click(Sender: TObject);
begin
showMessage(Label1.Caption);
Label1.Caption := 'Button';
end;
procedure TForm2.FormActivate(Sender: TObject);
begin
Label1.Caption := 'Activation';
end;
procedure TForm2.FormCreate(Sender: TObject);
begin
Label1.Caption := 'FormCreate';
DropRefPanel.Color := [=11=]BBF7B3 -50;
DropPanel := TmyPanel.Create(Form2);
with DropPanel do
begin
Parent := DropRefPanel;
Left := 3;
Top := 3;
Width := DropRefPanel.Width - 6;
Height := DropRefPanel.Height - 6;
Visible := True;
ParentBackground := False;
Color := [=11=]BBF7B3;
BevelOuter := bvLowered;
Caption := 'DropBox';
end;
end;
procedure TForm2.FormClose(Sender: TObject; var Action: TCloseAction);
begin
FreeAndNil(DropPanel);
end;
end.
DragAndDrop
单元的代码与 David 的代码相同。
我已经用 Label1
证明了这里的问题。
当我在 Drop()
过程中请求 Form2.Label1.Caption
时,它显示了设计时的 Label1
值,或者 FormCreate()
中分配的值,但不是来自 FormActivate()
的值或稍后在程序中分配的值。
好像有2种形式。
PS1:在 MainForm 中工作正常。
PS2:在 TmyPanel.Create(Form2)
中将 Form2
更改为 nil
不会改变行为。
PS3:将 Create()
函数移动到 OnActivate
不会改变行为。
PS4。我正在使用 Delphi XE4。
有人知道这个 ShowModal()
例子有什么问题吗?
显示模态表单时,您正在创建 TForm2
的新实例,但没有将其分配给 Drop()
试图访问的全局 Form2
变量。默认情况下,该全局变量仅用于自动创建的(即设计时)TForm2
对象,而不是动态创建的对象。
您试图将创建的 TForm2
对象指定为 TmyPanel
对象的 Owner
,但您使用的是全局 Form2
变量(它不t 指向创建的 TForm2
对象!)当你应该使用 FormCreate()
的隐式 Self
参数时,例如:
DropPanel := TmyPanel.Create({Form2}Self);
现在,Drop()
可以通过面板的Owner
属性访问表单,例如:
procedure TmyPanel.Drop(const FileNames: array of string);
var
i: Integer;
myFrm: TForm2;
begin
myFrm := Owner as TForm2;
myFrm.Label1.Caption := 'Drop';
begin
for i := 0 to Length(FileNames)-1 do
ShowMessage(myFrm.Label1.Caption + ': ' + FileNames[i]);
end;
end;
我正在使用 David Heffernan 在这里分享的一款软件:
How can I allow a form to accept file dropping without handling Windows messages?
我已经将组件从 Form 更改为 Panel,这在 MainForm 中工作正常。
但是,在 ShowModal()
环境中使用时,我无法访问模态表单中组件的值。
我做了一个小demo来说明这个问题。
Unit1:
unit Unit1;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Vcl.ExtCtrls, Unit2;
type
TForm1 = class(TForm)
Button1: TButton;
procedure Button1Click(Sender: TObject);
private
protected
Public
End;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.Button1Click(Sender: TObject);
Var aForm: TForm2;
Begin
aForm := TForm2.Create(Nil);
Try
aForm.ShowModal;
Finally
aForm.Free;
End;
End;
End.
第 2 单元:
unit Unit2;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.ExtCtrls, Vcl.StdCtrls, DragAndDrop;
type
TmyPanel = class(TPanel, IDragDrop)
private
FDropTarget: TDropTarget;
// implement IDragDrop
function DropAllowed(const FileNames: array of string): Boolean;
procedure Drop(const FileNames: array of string);
protected
// procedure WMDropFiles(var Message: TWMDropFiles); message WM_DROPFILES;
procedure CreateWindowHandle(Const Params: TCreateParams); override;
procedure DestroyWindowHandle; override;
end;
TForm2 = class(TForm)
DropRefPanel: TPanel;
Label1: TLabel;
Button1: TButton;
procedure FormCreate(Sender: TObject);
procedure FormClose(Sender: TObject; var Action: TCloseAction);
procedure FormActivate(Sender: TObject);
procedure Button1Click(Sender: TObject);
{ Private declarations }
public
{ Public declarations }
DropPanel: TmyPanel;
end;
var
Form2: TForm2;
implementation
{$R *.dfm}
procedure TmyPanel.CreateWindowHandle(Const Params: TCreateParams);
begin
inherited;
FDropTarget := TDropTarget.Create(WindowHandle, Self);
end;
procedure TmyPanel.DestroyWindowHandle;
begin
FreeAndNil(FDropTarget);
inherited;
end;
function TmyPanel.DropAllowed(const FileNames: array of string): Boolean;
begin
Result := True;
end;
procedure TmyPanel.Drop(const FileNames: array of string);
Var i: Integer;
begin
// Form2.Label1.Caption := 'Drop';
begin
for i := 0 to Length(FileNames)-1 do
ShowMessage(Form2.Label1.Caption + ': ' + FileNames[i]);
end;
end;
procedure TForm2.Button1Click(Sender: TObject);
begin
showMessage(Label1.Caption);
Label1.Caption := 'Button';
end;
procedure TForm2.FormActivate(Sender: TObject);
begin
Label1.Caption := 'Activation';
end;
procedure TForm2.FormCreate(Sender: TObject);
begin
Label1.Caption := 'FormCreate';
DropRefPanel.Color := [=11=]BBF7B3 -50;
DropPanel := TmyPanel.Create(Form2);
with DropPanel do
begin
Parent := DropRefPanel;
Left := 3;
Top := 3;
Width := DropRefPanel.Width - 6;
Height := DropRefPanel.Height - 6;
Visible := True;
ParentBackground := False;
Color := [=11=]BBF7B3;
BevelOuter := bvLowered;
Caption := 'DropBox';
end;
end;
procedure TForm2.FormClose(Sender: TObject; var Action: TCloseAction);
begin
FreeAndNil(DropPanel);
end;
end.
DragAndDrop
单元的代码与 David 的代码相同。
我已经用 Label1
证明了这里的问题。
当我在 Drop()
过程中请求 Form2.Label1.Caption
时,它显示了设计时的 Label1
值,或者 FormCreate()
中分配的值,但不是来自 FormActivate()
的值或稍后在程序中分配的值。
好像有2种形式。
PS1:在 MainForm 中工作正常。
PS2:在 TmyPanel.Create(Form2)
中将 Form2
更改为 nil
不会改变行为。
PS3:将 Create()
函数移动到 OnActivate
不会改变行为。
PS4。我正在使用 Delphi XE4。
有人知道这个 ShowModal()
例子有什么问题吗?
显示模态表单时,您正在创建 TForm2
的新实例,但没有将其分配给 Drop()
试图访问的全局 Form2
变量。默认情况下,该全局变量仅用于自动创建的(即设计时)TForm2
对象,而不是动态创建的对象。
您试图将创建的 TForm2
对象指定为 TmyPanel
对象的 Owner
,但您使用的是全局 Form2
变量(它不t 指向创建的 TForm2
对象!)当你应该使用 FormCreate()
的隐式 Self
参数时,例如:
DropPanel := TmyPanel.Create({Form2}Self);
现在,Drop()
可以通过面板的Owner
属性访问表单,例如:
procedure TmyPanel.Drop(const FileNames: array of string);
var
i: Integer;
myFrm: TForm2;
begin
myFrm := Owner as TForm2;
myFrm.Label1.Caption := 'Drop';
begin
for i := 0 to Length(FileNames)-1 do
ShowMessage(myFrm.Label1.Caption + ': ' + FileNames[i]);
end;
end;