【问题标题】:ShowModal on a created Form, no access to modal FormShowModal 在创建的表单上,无法访问模态表单
【发布时间】:2021-09-08 12:06:37
【问题描述】:

我正在使用 David Heffernan 在此处分享的软件:

How can I allow a form to accept file dropping without handling Windows messages?

我已将组件从表单更改为面板,并且在 MainForm 中运行良好。

但是,当在ShowModal() 环境中使用时,我无法访问模态表单中组件的值。

我做了一个小演示来展示这个问题。

单元1:

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 := $00BBF7B3 -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 := $00BBF7B3;
    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() 中的值或稍后分配的值在程序中。

好像有两种形式。

PS1:在 MainForm 中工作正常。

PS2:将TmyPanel.Create(Form2) 中的Form2 更改为nil 不会改变行为。

PS3:将 Create() 函数移动到 OnActivate 不会改变行为。

PS4。我正在使用 Delphi XE4。

有人知道这个ShowModal() 示例中有什么问题吗?

【问题讨论】:

  • Unit2.dfm 文件中是否存在 FormActivate?或者:在 FormCreate 中设置此值:OnActivate := FormActivate。我怀疑赋值已经丢失。
  • @Usauter 感谢您的反应。 .dfm 文件中确实存在 Formactivate。

标签: delphi modalpopup


【解决方案1】:

当显示模态表单时,您正在创建TForm2 的新实例,但没有将其分配给Drop() 试图访问的全局Form2 变量。默认情况下,该全局变量仅用于自动创建的(即设计时)TForm2 对象,而不是动态创建的对象。

您试图将创建的TForm2 对象分配为TmyPanel 对象的Owner,但您使用的是全局Form2 变量(它不指向创建的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;

【讨论】:

  • 感谢您的反应。不幸的是,这并不能解决我的问题。我理解你的建议。删除过程中的 label1.caption 分配被注释掉,因为我用它来测试。根据您的建议,表单上的原始 label1 仍未更改,我无法通过 de drop-procedure 访问它。
  • @Jan "这不能解决我的问题" - 那么你没有正确地提出你的实际问题。请编辑您的问题以更好地澄清问题。但是,我所描述的仍然是您显示的代码中的一个错误,因为Drop() 期望Form2 指向与实际指向不同的对象。所以无论如何你都需要解决这个问题。 “表单上的原始 label1 仍未更改” - 为什么要更改?你把它注释掉了!你没有多大意义。 “我无法通过 de drop-procedure 访问它。” - 我已经向您展示了如何做到这一点。
  • @Jan 没关系,我刚刚在您的代码中看到了另一个错误。我已经更新了我的答案来解决这个问题。
  • 感谢您的更新。奇迹般有效。很抱歉对于这个误会。我评论了它而你没有,所以这造成了混乱。我玩过 self、form2 和 nil,但由于您的第一个解决方案所涉及的问题而没有成功。我很感激。 PS。我知道有一个投票系统。我怎样才能为你投票?
  • @雷米。我已经投票了,但需要多沟通才能真正被接受。
猜你喜欢
  • 1970-01-01
  • 2021-01-03
  • 1970-01-01
  • 2015-04-29
  • 1970-01-01
  • 1970-01-01
  • 2016-08-28
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多