CS Matheus
CS Matheus

Reputation: 49

Programmatically check a custom treeview checkbox

I'm trying to programatically check a custom checkbox in a treeview. What I mean by custom, is that I call the below code to enable these checkboxes:

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

I tried the below code to check it, but it did not work.

  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;

Thanks in advance

Upvotes: 1

Views: 1130

Answers (2)

Dave Nottage
Dave Nottage

Reputation: 3602

What do you have TVIS_CHECKED defined as? It should be:

const
  TVIS_CHECKED = $2000;

Then, assuming Value is a Boolean of whether or not the item is checked:

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);

Upvotes: 1

Sertac Akyuz
Sertac Akyuz

Reputation: 54792

You have your state mask wrong, there's no TVIS_CHECKED state mask (in fact there is no TVIS_CHECKED, more on that later). Check boxes are managed through an image list, this is explained in the documentation.

Additionally, of course, you have to call 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;



Normally I'd advise to call TreeView_SetCheckState but the VCL has got a weird error in the translation of the macro.

This is the macro in the header:

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

where

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

This is why the made-up TVIS_CHECKED is $2000, the define shifts 2 12 bits left when fCheck is true (2 is the index of the checked image, 1 is unchecked).

This is VCL's translation:

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);

where IndexToStateImageMask is

Result := I shl 12;

Strangely, the VCL shifts fCheck 12 bits and then calls TreeView_SetItemState with a state that makes no sense for a state image mask (TVIS_FOCUSED (1), TVIS_SELECTED (2)).

This is XE2, I suggest to test the macro first if you are working with a later version.

Upvotes: 4

Related Questions