我正在尝试创建一个T
ShellListView的后代,它接受从
Windows资源管理器中删除的文件.我想处理组件定义中的拖放操作,而不必在任何使用该组件的应用程序中实现它(我已经找到了从Windows资源管理器中删除文件的示例,但所有这些都在应用程序/ TForm级别).
我在构造函数中调用DragAcceptFiles(),并为WM_DROPFILES定义了一个消息处理程序.但是,当我在示例项目中使用此组件并从Windows资源管理器中拖动文件时:
>我看到“未接受”图标(带斜线的圆圈),而不是我可以删除文件的指示.
>如果我确实试图删除文件,我听不到Beep().
我认为我没有正确警告Windows我的控件想接受拖动文件的事实.任何人都可以建议我缺少什么?
unit LJLShellListView; interface type TLJLShellListView = class(TShellListView) private procedure WMDropFiles(var Msg: TWMDropFiles); message WM_DROPFILES; published constructor Create(AOwner: TComponent); end; implementation uses ShellAPI; constructor TLJLShellListView.Create(AOwner: TComponent); begin inherited Create(AOwner); DragAcceptFiles(self.Handle,True); end; procedure TLJLShellListView.WMDropFiles(var Msg: TWMDropFiles); begin Beep(); // I never hear this. end; end.
解决方法
在问题的代码中,DragAcceptFiles调用需要ShellListView的窗口句柄.当代码访问wincontrol的句柄时,VCL检查窗口是否已创建,如果没有,VCL调用CreateHandle并继续创建窗口并返回其句柄.在这个阶段,问题中的代码成功注册了ShellListView的文件拖放窗口.但是有一个问题,控制还没有成为父级.当它将成为父级时,本机控件将被销毁,然后在其新父级中重新创建,当然将获得不同的句柄,使注册状态无效.
控件可能会因各种其他原因而重新创建.出于这个原因,最好将我们的代码放在重写的CreateWnd和DestroyWnd方法中,每当句柄发生变化或窗口即将被销毁时,我们的代码都会运行.