【问题标题】:How to change the ListView OnDrag image?如何更改 ListView OnDrag 图像?
【发布时间】:2013-07-31 23:28:15
【问题描述】:

我正在使用带有 ViewStyle := vsReport 的 ListView。当我将一行从一个点拖动到另一个点时,它会获取被拖动行的第一列的值(在这种情况下为 1)并将其显示在一个深灰色的矩形内,如下所示。

我尝试在 XE4 源代码中四处查看,但找不到设置此背景颜色的位置。我想将此背景颜色更改为 clSkyBlue (或类似的),但不知道它是如何完成的。

如何更改拖拽操作的默认深灰色背景图片?

【问题讨论】:

  • 找不到,VCL代码中没有设置背景色。 VCL 调用ListView_CreateDragImage 传递被拖动项目的索引,操作系统返回一个图像列表,稍后由ImageList_BeginDrag 拖动。
  • @SertacAkyuz 图片在这个 dll comctl32.dll 中,对吗?也许可以通过此方法添加图像:ImageList_AddIcon() 但我不确定,甚至更好,用此方法 ImageList_ReplaceIcon 替换它。但是,自定义它会更改整个操作系统的图像。
  • @SertacAkyuz 另外,图像索引为 0,请参见此处:SetDragImage(0, 2, 2); 在此过程中procedure TCustomTreeView.DoStartDrag(var DragObject: TDragObject);
  • @Matheus - 改变图像列表中的第一张图像没有问题,列表被创建和销毁一次拖动操作。

标签: delphi listview drag delphi-xe4


【解决方案1】:

VCL 的拖动操作没有开箱即用的拖动图像,但它确实提供了一种机制来提供要使用的拖动图像。这通常通过构建您自己的“拖动图像列表”来完成,或者通过覆盖控件本身的GetDragImages 方法(当使用内部拖动对象时),或者通过在开始拖动时构建您自己的“拖动对象”来完成, 并在其GetDragImages 方法中组装一个图像列表,以便在启动拖动时由 VCL 调用。

虽然TListViewTTreeView 控件的这种机制有点不同,因为底层的api 控件本身就支持为被拖动的项目提供拖动图像。因此,与其他控件不同,这些控件覆盖了它们的 GetDragImages 方法并返回在覆盖的 DoStartDrag 方法中创建的图像列表,其中控件要求 api 提供图像列表。这就是为什么您将无法在 VCL 代码中找到创建拖动图像的位置的原因。

要覆盖这种行为,可以覆盖后代类中的这些(可能还有其他一些)方法并实现它们。我不知道这是否容易,我发现通过在OnStartDrag 事件处理程序中构造拖动对象来提供图像列表更容易。这通常不会产生任何影响,因为在调用拖动对象的GetDragImages 时,VCL 已经确定了 api 提供的图像列表,并且 api 已经创建了一个正在拖动的临时列表。然后,我们可以强制将原始图像列表拖动到结束并替换我们自己的。

下面是一个过于简单的例子。除了错误处理、资源保护、热点确定等。查看 VCL 代码以了解它如何确保确实有一个正在被拖动的项目。

type
  TListWiewDragControlObjectEx = class(TDragControlObjectEx)
  protected
    function GetDragImages: TDragImageList; override;
  end;

function TListWiewDragControlObjectEx.GetDragImages: TDragImageList;
var
  Bmp: TBitmap;
  R: TRect;
begin
  Bmp := TBitmap.Create;
  Bmp.Canvas.Brush.Color := clSkyBlue;
  R := TListView(Control).Selected.DisplayRect(drBounds);
  Bmp.SetSize(R.Right - R.Left, R.Bottom - R.Top);
  Bmp.Canvas.Font := TListView(Control).Font;
  Bmp.Canvas.TextOut(0, 0, TListView(Control).Selected.Caption);

  Result := TDragImageList.Create(Control);
  Result.Width := Bmp.Width;
  Result.Height := Bmp.Height;
  ImageList_EndDrag;             // end the drag with the temporary list
  Result.SetDragImage(Result.Add(Bmp, nil), 0, 0);
  Bmp.Free;
end;

procedure TForm1.ListView1StartDrag(Sender: TObject;
  var DragObject: TDragObject);
begin
  DragObject := TListWiewDragControlObjectEx.Create(ListView1);
  DragObject.AlwaysShowDragImages := True;
end;

【讨论】:

  • 我试过这个,但我失去了放下物品的能力。它拖得很好,但是当我把它放到它的新位置时,什么也没有发生。奇怪的。我必须在以后的版本中列出这个。
  • @Cape - 我可能没试过放弃。稍后会尝试查看。
  • @Cape - 我在一个简单的测试中没有遇到任何问题。只要我在目标控件的OnDragDrop 事件处理程序中将Accept 设置为true,该控件的OnDragDrop 事件就会成功触发。包括列表视图本身。
猜你喜欢
  • 2016-07-21
  • 2012-04-18
  • 1970-01-01
  • 1970-01-01
  • 2017-11-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-10-25
相关资源
最近更新 更多