启用多选时的 TListBox 拖放问题

发布于 2024-07-06 21:38:20 字数 587 浏览 8 评论 0原文

我有一个 TListBox,其中 multiselect 和 ExtendedSelect 均设置为 true。 我需要能够拖动列表框中的多个项目来重新排列它们。 我的问题是,当用户单击已选择的项目而不按住 CTRL 或 SHIFT 键时会发生什么情况。

情况 1:DragMode 设置为 dmManual 在按下鼠标之前,选择将被清除。 这将不允许拖动多个项目。

情况 2:DragMode 设置为 dmAutomatic MouseDown 事件永远不会触发。 选择未清除,因此拖动是可以的,但用户无法通过单击所选项目之一来清除选择。 如果选择了所有项目或者用户想要选择的下一个项目是当前选择的一部分,这确实会导致问题。

请注意,仅当您在 OnStartDrag 过程中向 DragObject 分配某些内容时,才会出现此问题。 我认为如果 OnStartDrag 仅在用户移动鼠标后启动,问题就会消失。 我设置了 Mouse.DragImmediate := false,但是当我单击列表框中的某个项目时,我仍然会触发 StartDrag。

我在这个项目中使用 Delphi 7,但我在 Delphi 2007 中看到了相同的行为。

I have a TListBox with multiselect and ExtendedSelect both set to true. I need to be able to drag multiple items in the list box to re-arrange them. My problem is what happens when the user clicks on an item that is already selected without holding down the CTRL or SHIFT key.

Case 1: DragMode is set to dmManual
The selection is cleared before the mouse down. This will not allow multiple items to be dragged.

Case 2: DragMode is set to dmAutomatic
The MouseDown event never fires. The selection is not cleared so dragging is OK, but the user cannot clear the selection by clicking on one of the selected items. This really causes a problem if all the items are selected or the next item the user wants to select was part of the current selection.

Note that this problem only happens if you assign something to the DragObject in the OnStartDrag procedure. I think the problem would go away if OnStartDrag would only start after the user moves the mouse. I have Mouse.DragImmediate := false set but I still get the StartDrag fired as soon as I click on an item in the list box.

I am using Delphi 7 for this project but I see the same behavior in Delphi 2007.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

银河中√捞星星 2024-07-13 21:38:20

我已经玩这个有一段时间了。 并观察相同的效果。

我将使用 Case2 并向列表添加一个(全选/取消全选)按钮。 它甚至添加了额外的功能并解决了问题中最烦人的部分。

I have played with this for a while. And observe the same effects.

I would use Case2 and add a (Select All/Deselect All) button to the list. It even adds extra functionality and solves the most annoying part of the problem.

时光与爱终年不遇 2024-07-13 21:38:20

使用案例 2 以及当 TListBox.OnMouseUp 事件触发时,检查是否选择并拖动了多个项目。 如果选择了多个项目,但未拖动,则取消选择除单击的项目之外的所有项目。

我会使用这种方法,因为 Windows 资源管理器就是这样工作的。

Use Case 2 and when the TListBox.OnMouseUp event fires check to see if multiple items are selected and were dragged. If multiple items are selected, but weren't dragged, then deselect all items apart from the clicked item.

I would use this method because Windows Explorer works this way.

夏尔 2024-07-13 21:38:20

有点拼凑,但这很有效。 ListBox 上的 DragMode 设置为 dmAutomatic。

procedure TForm1.ListBox1DragDrop(Sender, Source: TObject; X, Y: Integer);
var
  iDropIdx, i: Integer;
  pDropPoint: TPoint;
  slSelected: TStrings;
begin
  {Which item is being dropped onto?}
  pDropPoint := Point(X, Y);
  iDropIdx := ListBox1.ItemAtPos(pDropPoint, False);

  slSelected := TStringList.Create;
  try
    {Copy the selected items to another string list}
    for i := 0 to Pred(ListBox1.Items.Count) do
    begin
      if (ListBox1.Selected[i]) then
        slSelected.Append(ListBox1.Items[i]);
    end;

    {Find the selected items in the listbox and swap them with the drop target}
    for i := 0 to Pred(slSelected.Count) do
    begin
      ListBox1.Items.Exchange(ListBox1.Items.IndexOf(slSelected[i]), iDropIdx);
      inc(iDropIdx);
    end;
  finally
    slSelected.Free;
  end;
end;

Bit of a kludge but this works. DragMode on the ListBox is set to dmAutomatic.

procedure TForm1.ListBox1DragDrop(Sender, Source: TObject; X, Y: Integer);
var
  iDropIdx, i: Integer;
  pDropPoint: TPoint;
  slSelected: TStrings;
begin
  {Which item is being dropped onto?}
  pDropPoint := Point(X, Y);
  iDropIdx := ListBox1.ItemAtPos(pDropPoint, False);

  slSelected := TStringList.Create;
  try
    {Copy the selected items to another string list}
    for i := 0 to Pred(ListBox1.Items.Count) do
    begin
      if (ListBox1.Selected[i]) then
        slSelected.Append(ListBox1.Items[i]);
    end;

    {Find the selected items in the listbox and swap them with the drop target}
    for i := 0 to Pred(slSelected.Count) do
    begin
      ListBox1.Items.Exchange(ListBox1.Items.IndexOf(slSelected[i]), iDropIdx);
      inc(iDropIdx);
    end;
  finally
    slSelected.Free;
  end;
end;
尹雨沫 2024-07-13 21:38:20

我不确定为什么这会产生影响,但如果我将 DragObject 更改为 TDragControlObjectEx (而不是 TDragObjectEx),我就会得到我正在寻找的行为。 拖动模式设置为自动。

我试图看看这会产生什么影响,但我无法弄清楚。

I'm not sure why this makes a difference but if I change the DragObject to be a TDragControlObjectEx (instead of a TDragObjectEx) I get the behavior I am looking for. Drag mode is set to Automatic.

I tried to look and see what this was affecting but I could not figure it out.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文