How can Virtual Treeview control be made to always scroll by lines?
Asked Answered
N

2

5

The Virtual Treeview scrolls vertically by pixels, unlike the way the standard Delphi grids, TListView and TTreeView (or most of the other such controls that I am aware of) scroll by line and keep a full line visible at the top of the control at all times. When I use the cursor keys to navigate, then depending on direction either the first or the last line is completely visible. When scrolling with the mouse there is no alignment whatsoever.

This behaviour can be observed for example with the Structure window in Delphi 2007 and 2009.

Is there any way to set the many properties to have the behaviour of the standard windows controls? Or is there a set of patches somewhere to achieve this?

Nonlegal answered 30/5, 2009 at 11:47 Comment(0)
Y
5

You could intercept the TBaseVirtualTree.OnScroll event and use the virtual treeview's canvas's return value for textheight('M') as the amount to change TBaseVirtualTree.offsety in order to increment (scroll up) or decrement (scroll down). Could also test to ensure that pre-scroll position modulus textheight('M') is zero (to avoid scrolling by the right amount from the wrong position).

Alternatively, this post on the Virtual Treeview forum suggests another approach: hide the virtual treeview's native scroll bars with VCL scroll bars and then do the scrolling yourself (trapping VCL scroll events and programmatically scrolling the virtual treeview).

Yoko answered 1/6, 2009 at 1:6 Comment(3)
Thanks for your answer, I tried the first alternative only as I want to keep the original scrollbars. It has the problem that the last row isn't going to be completely visible unless the control adds some empty space below the last node when the client height isn't a multiple of the node height. I assume that the scrolling code needs to be adapted in the control if what I want isn't supported out-of-the-box.Nonlegal
Well, your answer gave me the necessary push - there is actually another property BottomSpace, and using them both it seems to work as I want it to. I'm marking yours as accepted, but will add the code in another answer.Nonlegal
Always glad to give a friend a push! Actually, I really have enjoyed reading your SO posts, so helping in any way is a pleasure.Yoko
N
6

This is what I came up with the help of Argalatyr, looks like it does what I want it to:

procedure TForm1.FormCreate(Sender: TObject);
begin
  VirtualStringTree1.ScrollBarOptions.VerticalIncrement :=
    VirtualStringTree1.DefaultNodeHeight;
end;

procedure TForm1.VirtualStringTree1Resize(Sender: TObject);
var
  DY: integer;
begin
  with VirtualStringTree1 do begin
    DY := VirtualStringTree1.DefaultNodeHeight;
    BottomSpace := ClientHeight mod DY;
    VirtualStringTree1.OffsetY := Round(VirtualStringTree1.OffsetY / DY) * DY;
  end;
end;

procedure TForm1.VirtualStringTree1Scroll(Sender: TBaseVirtualTree; DeltaX,
  DeltaY: Integer);
var
  DY: integer;
begin
  if DeltaY <> 0 then begin
    DY := VirtualStringTree1.DefaultNodeHeight;
    VirtualStringTree1.OffsetY := Round(VirtualStringTree1.OffsetY / DY) * DY;
  end;
end;
Nonlegal answered 1/6, 2009 at 14:3 Comment(1)
I realize that this answer is now 12 years or so old, but I was just looking into this exact issue and this helped a lot. Note that the change above affects keyboard navigation as well as thumbtracking which can cause the bottom focused node to only be partially visible. My fix was to only change OffsetY in OnScroll if tsThumbTracking is in TreeStates.Neaten
Y
5

You could intercept the TBaseVirtualTree.OnScroll event and use the virtual treeview's canvas's return value for textheight('M') as the amount to change TBaseVirtualTree.offsety in order to increment (scroll up) or decrement (scroll down). Could also test to ensure that pre-scroll position modulus textheight('M') is zero (to avoid scrolling by the right amount from the wrong position).

Alternatively, this post on the Virtual Treeview forum suggests another approach: hide the virtual treeview's native scroll bars with VCL scroll bars and then do the scrolling yourself (trapping VCL scroll events and programmatically scrolling the virtual treeview).

Yoko answered 1/6, 2009 at 1:6 Comment(3)
Thanks for your answer, I tried the first alternative only as I want to keep the original scrollbars. It has the problem that the last row isn't going to be completely visible unless the control adds some empty space below the last node when the client height isn't a multiple of the node height. I assume that the scrolling code needs to be adapted in the control if what I want isn't supported out-of-the-box.Nonlegal
Well, your answer gave me the necessary push - there is actually another property BottomSpace, and using them both it seems to work as I want it to. I'm marking yours as accepted, but will add the code in another answer.Nonlegal
Always glad to give a friend a push! Actually, I really have enjoyed reading your SO posts, so helping in any way is a pleasure.Yoko

© 2022 - 2024 — McMap. All rights reserved.