我最近为Delphi(2009版)编写的大型应用程序添加了一项功能,允许用户从Windows资源管理器中拖动文件并将其放在TcxGrid控件上。我通过将我自己的窗口proc附加到网格并拦截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的所有消息的整数值直接输出到单独的日志窗口而不是首先输出到字符串列表缓冲区,也会出现这种情况。我希望有人能够提供一些线索,了解为什么会发生这种情况或如何使其发挥作用。

有帮助吗?

解决方案

不应使用WM_DROPFILES消息,而应使用OLE Drag'n'Drop。查看RegisterDropTarget API。您可以获得有关哪里正在进行拖放的更详细信息。您还可以接受更多种类的拖动对象。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top