我最近向一个用 Delphi(2009 版)编写的大型应用程序添加了一项功能,该功能允许用户从 Windows 资源管理器中拖动文件并将它们放到 TcxGrid 控件上。我通过将我自己的窗口过程附加到网格并拦截 WM_DROPFILES 消息的常用方法实现了这一点:
originalGridWindowProc := cxGrid.WindowProc; // remember the old one
cxGrid.WindowProc := GridWindowProc; // assign the new one
DragAcceptFiles(cxGrid.Handle, LongBool(True)); // setup to accept dropped files
我现在正在尝试增强此功能以检测用户何时将文件拖放到网格中的现有行上,这将开始使用新版本覆盖现有文件的过程。
我的第一个想法是看看网格控件的鼠标悬停事件是否有效。确实如此,但不是在拖动操作期间。
然后我使用了一个名为 Winspector 的程序来查看当鼠标在网格上移动时哪些消息被发送到网格控件,我现在可以检测鼠标在哪一行并突出显示它。我使用与上面相同的技术,但在这种情况下,我将覆盖 GridSite 的窗口过程,而不是网格本身,因为根据 Winspector,消息似乎是在哪里:
originalGridSiteWindowProc := cxGrid.ActiveView.Site.WindowProc;
cxGrid.ActiveView.Site.WindowProc := GridSiteWindowProc;
这是 GridSiteWindowProc 的主体:
procedure Tfrm.GridSiteWindowProc(var message: TMessage);
var
hitTest: TcxCustomGridHitTest;
gridRecord: TcxCustomGridRecord;
begin
//Log(IntToStr(message.Msg));
case message.Msg of
WM_NCHITTEST: begin
hitTest := cxGrid.ActiveView.GetHitTest(cxGrid.ScreenToClient(Mouse.CursorPos));
if hitTest is TcxGridRecordCellHitTest then begin
gridRecord := TcxGridRecordCellHitTest(HitTest).GridRecord;
if Not gridRecord.Focused then
gridRecord.Focused := True;
end;
originalGridSiteWindowProc(message);
end
else
originalGridSiteWindowProc(message);
end;
end;
如您所见,我正在捕获 WM_NCHITTEST 消息以实现此目的。根据 Winspector,在拖动操作期间,此消息也会发送到网格站点窗口,但如果我取消注释 Log() 语句,该语句会将消息值输出到字符串列表(之后我手动转储到备注字段),我已经确定由于某种原因,在网格上拖动文件时,我只会收到其中一两条消息。
现在 - 这是有趣的部分:如果我让 Winspector 运行并监视消息进入该窗口,我会在文件拖动操作期间突然开始收到所有 WM_NCHITTEST 消息。如果我将进入窗口 proc 的所有消息的整数值直接输出到单独的日志窗口而不是首先输出到字符串列表缓冲区,情况也是如此。我希望有人能够提供一些线索,说明为什么会发生这种情况或如何让它发挥作用。