Question

Checkbox handling in version 5.0.0 of VirtualTrees.pas appears broken when toThemeAware is enabled. Nodes that are csUncheckedNormal are drawn as checked + hot.

To correctly paint an unchecked, themed checkbox using DrawElement, the Details record must be : Element = teButton, Part = 3, and State = 5. However, VirtualTrees.pas ends up calling DrawElement with State = 1 when a node is set to csUncheckedNormal.

There seems to be a good deal of indirection and extra constants declared in VirtualTrees, so I'm not sure how best to fix this. Ideas welcomed...

(Even the minimal code to get a TVirtualStringTree on screen and filled with some data is a bit lengthy to post here. Aside from the basics, all that's needed to reproduce this is to enable toCheckSupport in TreeOptions.MiscOptions, and set Node.CheckType := ctTriStateCheckBox in the InitNode callback.)

Was it helpful?

Solution

Well, since I think the VirtualTreeView does not count with the VCL styles when porting to delphi XE2, this might light up to solve your problem. You have to get element details before you draw it, otherwise you'll get something like this (it's the simulation of how the VirtualTreeView paint check box states). Notice the different order and the artifacts; it's the result of the same code once with VCL styles disabled, second time enabled:

enter image description here

Quite strange I know, but I can't answer you why is this happening. I can just tell you that you should call the TThemeServices.GetElementDetails or optionally calculate the state index by your own to get the element rendering to work properly. You may try to use the following fix:

procedure TBaseVirtualTree.PaintCheckImage(Canvas: TCanvas; 
  const ImageInfo: TVTImageInfo; Selected: Boolean);
var
  // add a new variable for calculating TThemedButton state from the input
  // ImageInfo.Index; I hope ImageInfo.Index has the proper state order
  State: Integer;
begin
...
  case Index of
    0..8: // radio buttons
    begin
      // get the low index of the first radio button state and increment it by 
      // the ImageInfo.Index and get details of the button element
      State := Ord(TThemedButton(tbRadioButtonUncheckedNormal)) + Index - 1;
      Details := StyleServices.GetElementDetails(TThemedButton(State));
    end;
    9..20: // check boxes
    begin
      // get the low index of the first check box state and increment it by 
      // the ImageInfo.Index and get details of the button element
      State := Ord(TThemedButton(tbCheckBoxUncheckedNormal)) + Index - 9;
      Details := StyleServices.GetElementDetails(TThemedButton(State));
    end;
    21..24: // buttons
    begin
      // get the low index of the first push button state and increment it by 
      // the ImageInfo.Index and get details of the button element
      State := Ord(TThemedButton(tbPushButtonNormal)) + Index - 21;
      Details := StyleServices.GetElementDetails(TThemedButton(State));
    end;
  else
    Details.Part := 0;
    Details.State := 0;
  end;
...
end;

I've tested this for all check types and it works for me.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top