Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Incorrect PaintTree behavior in TVirtualStringTree when using poUnbuffered #579

Closed
Matterdor opened this issue Aug 31, 2015 · 1 comment
Closed
Assignees
Labels
Milestone

Comments

@Matterdor
Copy link

There seems to be a bug with the PaintTree logic in TVirtualStringTree when using the poUnbuffered option. Only the first node of the tree is visible in the output. I tested using the Minimal VST example and the behavior is identical. When poUnbuffered is used as an option then only the first node is visible, remove the option and the tree is correctly painted.

If I step through the code then all of the objects are being painted on the canvas so it looks like a clipping issue but I have not worked with VST enough to identify what the problem is. They play a lot with the canvas origin and clipping.

To see the problem in action, just put the following code on any form that includes a VST, change the names to protect the innocent as required and click away.

procedure TMainForm.Button2Click(Sender: TObject);
var
  saveBitmap: TBitmap;
begin
  saveBitmap := TBitmap.Create;
  try
    saveBitmap.height := 400;
    saveBitmap.width := 400;

    vst.PaintTree(
      saveBitmap.Canvas,
      Rect(0, 0, 400, 400),
      Point(0, 0),
      [poBackground, poColumnColor, poGridLines, poUnbuffered], // Remove poUnbuffered to have the tree paint correctly
      pfDevice     // pixelformat
      );

    saveBitmap.SaveToFile('E:\temp\CanvasSave' + FormatDateTime('hhnnsszzz', Now) + '.bmp');
  finally
    saveBitmap.Free; 
  end;
end;

My fix for the code is as follows:

In change line 30219 of the latest master VirtualTrees.pas as follows. The commented out line of code and the new replacement line of code below.

          if not (poUnbuffered in PaintOptions) then
          begin
            // Adjust height of temporary node bitmap.
            with NodeBitmap do
            begin
              if Height <> PaintInfo.Node.NodeHeight then
              begin
                // Avoid that the VCL copies the bitmap while changing its height.
                Height := 0;
                Height := PaintInfo.Node.NodeHeight;
                SetCanvasOrigin(Canvas, Window.Left, 0);
              end;
            end;
          end
          else
          begin
            SetCanvasOrigin(PaintInfo.Canvas, -TargetRect.Left + Window.Left, -TargetRect.Top);
            // This line below is wrong
            // ClipCanvas(PaintInfo.Canvas, Rect(TargetRect.Left, TargetRect.Top, TargetRect.Right,
            //                                   Min(TargetRect.Bottom, MaximumBottom)))
            // This is the updated line of code
            ClipCanvas(PaintInfo.Canvas, Rect(0, 0, TargetRect.Right - TargetRect.Left,
                                              Min(TargetRect.Bottom - TargetRect.Top, MaximumBottom - TargetRect.Top)));
          end;

Apparently SetCanvasOrigin is changing the origin and the ClipCanvas is not taking these changes into account.

I put this up on StackOverflow a while back and didn't think much more on it suddenly occurred to me to push the fix through to you.

http://stackoverflow.com/questions/22055775/incorrect-painttree-behavior-in-tvirtualstringtree-when-using-pounbuffered

It may not work in all cases but it seems to work in all of the ones that I have tested.

@joachimmarder
Copy link
Contributor

Thanks for the fix, it is now part of the official repository.

# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants