【问题标题】:Programmatically check a custom treeview checkbox以编程方式检查自定义树视图复选框
【发布时间】:2020-02-14 20:42:12
【问题描述】:

我正在尝试以编程方式检查树视图中的自定义复选框。我所说的自定义是指我调用下面的代码来启用这些复选框:

SetWindowLong(TreeView1.Handle, GWL_STYLE, GetWindowLong(TreeView1.Handle, GWL_STYLE) or TVS_CHECKBOXES)

我尝试了下面的代码来检查它,但它不起作用。

  Node := TreeView1.Selected;
  TVItem.mask := TVIF_STATE;
  TVItem.hItem := Node.ItemId;
  TreeView_GetItem(Node.TreeView.Handle, TVItem);
  TVItem.stateMask := TVIS_CHECKED;
  TVItem.mask := TVIS_CHECKED;

提前致谢

【问题讨论】:

  • TreeView_SetItem 在哪里?
  • 顺便说一句,在你走得更远之前,请参阅this 答案。

标签: delphi


【解决方案1】:

你的状态掩码有误,没有TVIS_CHECKED 状态掩码(实际上没有TVIS_CHECKED,稍后会详细介绍)。复选框通过图像列表进行管理,documentation 对此进行了说明。

另外,当然,你必须打电话给TreeView_SetItem

const
  TVIS_CHECKED = 2 shl 12;
var
  Node: TTreeNode;
  TVItem: TTVItem;
begin
  Node := TreeView1.Selected;
  if Assigned(Node) then begin
    TVItem.mask := TVIF_STATE;
    TVItem.hItem := Node.ItemId;
    TreeView_GetItem(Node.TreeView.Handle, TVItem);

    TVItem.stateMask := TVIS_STATEIMAGEMASK;
    TVItem.state := TVIS_CHECKED;
    TreeView_SetItem(Node.TreeView.Handle, TVItem);
  end;
end;



通常我会建议打电话给TreeView_SetCheckState,但VCL 在宏的翻译中有一个奇怪的错误。

这是标题中的宏:

#define TreeView_SetCheckState(hwndTV, hti, fCheck) \
  TreeView_SetItemState(hwndTV, hti, INDEXTOSTATEIMAGEMASK((fCheck)?2:1), TVIS_STATEIMAGEMASK)

在哪里

#define INDEXTOSTATEIMAGEMASK(i) ((i) << 12)

这就是为什么虚构的TVIS_CHECKED 是 2000 美元,当fCheck 为真时,定义向左移动 2 个 12 位(2 是选中图像的索引,1 是未选中)。

这是VCL的翻译:

function TreeView_SetCheckState(hwndTV: HWND; hti: HTreeItem; fCheck: BOOL): UINT;
var
  LState: UINT;
begin
  if IndexToStateImageMask(Integer(fCheck)) = 0 then
    LState := 1
  else
    LState := 2;
  Result := TreeView_SetItemState(hwndTV, hti, LState, TVIS_STATEIMAGEMASK);

IndexToStateImageMask 在哪里

Result := I shl 12;

奇怪的是,VCL 将 fCheck 移动了 12 位,然后调用 TreeView_SetItemState,其状态对于状态图像掩码没有意义(TVIS_FOCUSED (1)、TVIS_SELECTED (2))。

这是 XE2,如果您使用更高版本,我建议先测试宏。

【讨论】:

  • Sertac Akyuz,非常感谢您的帮助,它按预期工作。我也了解了更多关于 VCL 的知识。通常我不会深入了解 Windows 文档。再次感谢
  • 以同样的方式,你知道我怎样才能在每次触发时获得一个事件吗?示例:当用户单击复选框时,它会触发“OnChecking”事件?
  • 不客气。常规的 onclick 似乎适合鼠标点击。但是,当您使用键盘切换项目的状态时,AFAICT 触发的唯一通知是 onget[selected|image]index。当然还有关键。可能实现将涵盖按键和点击,可能会导致一些意大利面条代码。我猜这将是一个有效的问题。
  • 再次感谢 Sertac,我将尝试使用 Click 和 Key Up/Down!
【解决方案2】:

您将 TVIS_CHECKED 定义为什么?应该是:

const
  TVIS_CHECKED = $2000;

然后,假设 Value 是一个布尔值,表示该项目是否被检查:

FillChar(TVItem, SizeOf(TVItem), 0);
TVItem.hItem := Node.ItemId;
TVItem.mask := TVIF_STATE;
TVItem.stateMask := TVIS_STATEIMAGEMASK;
if Value then
  TVItem.state := TVIS_CHECKED
else
  TVItem.state := TVIS_CHECKED shr 1;
TreeView_SetItem(Node.Handle, TVItem);

【讨论】:

  • 确实是我丢失的 SetItem
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-06-07
  • 2017-06-18
  • 1970-01-01
  • 2012-08-12
  • 2012-10-01
  • 1970-01-01
  • 2019-07-16
相关资源
最近更新 更多