在创建的表单上显示模态,无法访问模态表单

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;