【问题标题】:Handling WM_DROPFILES message doesn't work in Lazarus处理 WM_DROPFILES 消息在 Lazarus 中不起作用
【发布时间】:2016-10-28 12:07:33
【问题描述】:

我想使用 Lazarus 创建 Windows GUI 应用程序,该应用程序能够将文件从资源管理器拖到 TEdit 小部件并显示文件路径。

我已经阅读并尝试了一些 delphi 教程,它说您需要处理 WM_DROPFILES 消息,但我仍然无法使其正常工作。所以我在想我是否应该首先尝试简单的方法,让应用程序能够将文件拖动到 TForm。

所以我关注了this example,但也没有用。

这里是完整的代码:

unit Unit1;

{$mode objfpc}{$H+}

interface

uses
  Windows, Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs,
  ShellAPI;

type

  { TForm1 }

  TForm1 = class(TForm)
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
  private
    { private declarations }
  public
    { public declarations }
  protected
      procedure WMDropFiles(var Msg: TMessage); message WM_DROPFILES;
  end;

var
  Form1: TForm1;

implementation

{$R *.lfm}

{ TForm1 }

procedure TForm1.FormCreate(Sender: TObject);
begin
  DragAcceptFiles(self.Handle, True);
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
  DragAcceptFiles(self.Handle, False);
end;

procedure TForm1.WMDropFiles(var Msg: TMessage);
begin
  ShowMessage('hello');  // never gets called
end;

end. 

TForm1.FormCreateTForm1.FormDestroy 工作正常,但永远不会调用 TForm1.WMDropFiles 方法。

有人知道解决办法吗? Lazarus/Free-Pascal windows 库的行为可能与 Delphi 的不同吗?

仅供参考,我在 Windows 7 64 位上使用 lazarus-1.6.0-fpc-3.0.0-win32。

【问题讨论】:

  • 应该是number 2
  • 不,我已经检查了 lazarus 应用程序进程具有与资源管理器进程相同的中等优先级。我还制作了具有相同功能且运行良好的 c++ 应用程序。
  • 依赖窗体的窗口不被重新创建是一个很大的错误。创建一个您可以控制其生命的窗口句柄。在 Delphi 中分配 HWnd。
  • @DavidHeffernan:如果我错了,请纠正我,Lazarus 中似乎不存在 AllocateHWnd。
  • @david:不,我知道这意味着什么。谢谢。

标签: drag-and-drop lazarus freepascal


【解决方案1】:

DragAcceptFiles 不正确(对于 Lazarus),因为它是依赖于平台的代码))

有正确的跨平台代码:OnDropFiles - Only works with dock icon, not with Application Form

他不使用“Windows”、“Messages”和“ShellAPI”。

1 将MainForm的“AllowDropFiles”属性设置为True;

2 程序声明:

  type
  { TMainForm }
  TMainForm = class(TForm)
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
  private
    procedure OnApplicationDropFiles(Sender: TObject; const FileNames: array of String);
  public  
  end;

3 程序:

procedure TMainForm.FormCreate(Sender: TObject);
begin
  Application.AddOnDropFilesHandler(@OnApplicationDropFiles);
end;  

procedure TMainForm.OnApplicationDropFiles(Sender: TObject; const FileNames: array of String);
begin
  ShowMessage('Files dropped');
end;

procedure TMainForm.FormDestroy(Sender: TObject);
begin
  Application.RemoveOnDropFilesHandler(@OnApplicationDropFiles);
end;

【讨论】:

  • 除了添加和删除 OnApplicationDropFiles 处理程序之外,您还可以使用直接提供 OnDropFiles 事件的 TApplicationProperties 组件。 - 或者您可以使用表单的 OnDropFiles 事件,就像 eugene 在 7 月 25 日所做的那样。
  • 这对仅在“编辑”小部件上拖放文件有何帮助?
【解决方案2】:

下面的答案仅详细说明了问题显然是关于 Win32WidgetSet 的。

首先,作为对所提问题的回答,不调用表单的WM_DROPFILES 处理程序的原因是,消息没有传递到相应的窗口过程发送消息的控制类。 LCL 代码在交付的消息中具有选择性。一些细节在下一段,可以安全跳过...


消息发送后(Win32Int.pp中的“win32object.inc”过程TWin32WidgetSet.AppProcessMessages中Win32 API的DispatchMessage,这是主消息循环),控件窗口的窗口过程(函数@987654325 “Win32Int.pp”中“win32callback.inc”的@)构造一个WindowProcHelper对象并调用它的DoWindowProc(仍在“win32callback.inc”中)函数。这个函数有一个巨大的消息案例,这里决定一条消息是否会通过DeliverMessage函数(在“LCLMessageGlue.pp”中)。 WM_DROPFILES 的处理方式不同,然后它不会“交付”。任何发送到DeliverMessage 的消息都会传递到它所发送的控件所属的控件类的窗口过程(“controls.pp”的“control.inc”中的TControl.WndProc,或任何覆盖,fi @987654332 @ 在“controls.pp”的“wincontrol.inc”中),如果它是一个控件,否则分派。

其次,为了实现在编辑控件上处理拖放文件的期望行为,一个明显的解决方案,在很多地方都提到过——即使在拉撒路的文档中链接到问题的评论中,也是对窗口的子类化控制。您的子类将在 LCL 有机会处理它之前传递消息,因此您可以对消息采取行动。

但是,一旦您在 "win32callback.inc" 中跟踪 TWindowProcHelper.HandleDropFiles 中的代码,很明显在 LCL 中设置 WM_DROPFILES 的特殊处理是多么容易,以便只有编辑控件处理丢弃的文件.通常这是在previous answer 中提到的表单级别进行处理,但表单实际上也代表其子级接收到的消息。

不需要详细说明,因为它只是实现细节,我不知道它是否有意,但是,将表单的AllowDropFiles设置为true,然后在表单的OnCreate处理程序中,取消注册表单作为放置目标(自动注册)并注册编辑。

procedure TForm1.FormCreate(Sender: TObject);
begin
  AllowDropFiles:= True;
  DragAcceptFiles(Handle, False);
  DragAcceptFiles(Edit1.Handle, True);
end;

只有编辑会接受文件,但您仍会在表单的事件处理程序上处理它。

procedure TForm1.FormDropFiles(Sender: TObject; const FileNames: array of String);
begin
  if Length(FileNames) > 0 then
    Edit1.Text := FileNames[0];
end;


同样的设置后也可以使用Application.OnDropFiles,但我看不出比以前的方法有什么优势。

【讨论】:

    【解决方案3】:
    procedure TForm1.FormDropFiles(Sender: TObject; const FileNames: array of String);
    var i   : Integer;
        aTxt: String;
    begin
        showmessage('oh it works, this is filename #1 ' + filenames[0])
    end;
    

    【讨论】:

    • 对不起,这不是我想要的,再看我的问题帖,前两段解释了我想要实现的目标。
    猜你喜欢
    • 1970-01-01
    • 2013-01-20
    • 2017-12-25
    • 1970-01-01
    • 2019-08-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多