2012-04-15 5 views
1

У меня есть узлы с переменной высотой. Если высота прокрученного узла больше, чем клиентская область VST, вызов функции «ScrollIntoView (GetLast, False, False)» в первый раз делает работу отлично, и она перескакивает на конец последнего узла, который является хорошим.TVirtualStringTree: прокрутка до дна два раза приводит к переключению

Но вызов этой же функции снова вызывает прокрутку до начала последнего узла. Это какая-то особенность? Я не хочу этого, как отключить?

Я проверил функцию ScrollIntoView, чтобы понять причину. При первом вызове R.Top равен 0, поэтому он переходит в другую часть, которая дает ожидаемый результат. Но со вторым вызовом он обнаруживает, что R.Top отрицательный, и делает, если часть, которая вызывает прокрутку до начала последнего узла, который не нужен.

Любое предложение?

This is OnTimer event: (500ms) 
procedure TMainForm.SyncHexLog; 
begin 
    Try 
    if (HexLog.RootNodeCount <> FirpList.ComOperationCountLagged) then 
     begin 
     HexLog.RootNodeCount := FirpList.ComOperationCountLagged; 

     // measure for fast scroling 
     HexLog.ReInitNode(HexLog.GetLastNoInit(), True); 

     if FAutoScroll then 
      begin 
      //HexLog.ScrollToTheBottom(); 
      HexLog.ScrollIntoView(HexLog.GetLast(), False, False); 
      end; 
     end; 
    Finally 
    End; 
end; 

function TBaseVirtualTree.ScrollIntoView(Node: PVirtualNode; Center: Boolean; Horizontally: Boolean = False): Boolean; 

// Scrolls the tree so that the given node is in the client area and returns True if the tree really has been 
// scrolled (e.g. to avoid further updates) else returns False. If extened focus is enabled then the tree will also 
// be horizontally scrolled if needed. 
// Note: All collapsed parents of the node are expanded. 

var 
    R: TRect; 
    Run: PVirtualNode; 
    UseColumns, 
    HScrollBarVisible: Boolean; 
    ScrolledVertically, 
    ScrolledHorizontally: Boolean; 

begin 
    ScrolledVertically := False; 
    ScrolledHorizontally := False; 

    if Assigned(Node) and (Node <> FRoot) then 
    begin 
    // Make sure all parents of the node are expanded. 
    Run := Node.Parent; 
    while Run <> FRoot do 
    begin 
     if not (vsExpanded in Run.States) then 
     ToggleNode(Run); 
     Run := Run.Parent; 
    end; 
    UseColumns := FHeader.UseColumns; 
    if UseColumns and FHeader.FColumns.IsValidColumn(FFocusedColumn) then 
     R := GetDisplayRect(Node, FFocusedColumn, not (toGridExtensions in FOptions.FMiscOptions)) 
    else 
     R := GetDisplayRect(Node, NoColumn, not (toGridExtensions in FOptions.FMiscOptions)); 

    // The returned rectangle can never be empty after the expand code above. 
    // 1) scroll vertically 
    if R.Top < 0 then // <==== what is the purpose of this if, I need always else part 
    begin 
     if Center then 
     SetOffsetY(FOffsetY - R.Top + ClientHeight div 2) 
     else 
     SetOffsetY(FOffsetY - R.Top); 
     ScrolledVertically := True; 
    end 
    else 
     if (R.Bottom > ClientHeight) or Center then 
     begin 
     HScrollBarVisible := (ScrollBarOptions.ScrollBars in [ssBoth, ssHorizontal]) and 
      (ScrollBarOptions.AlwaysVisible or (Integer(FRangeX) > ClientWidth)); 
     if Center then 
      SetOffsetY(FOffsetY - R.Bottom + ClientHeight div 2) 
     else 
      SetOffsetY(FOffsetY - R.Bottom + ClientHeight); 
     // When scrolling up and the horizontal scroll appears because of the operation 
     // then we have to move up the node the horizontal scrollbar's height too 
     // in order to avoid that the scroll bar hides the node which we wanted to have in view. 
     if not UseColumns and not HScrollBarVisible and (Integer(FRangeX) > ClientWidth) then 
      SetOffsetY(FOffsetY - GetSystemMetrics(SM_CYHSCROLL)); 
     ScrolledVertically := True; 
     end; 

    if Horizontally then 
     // 2) scroll horizontally 
     ScrolledHorizontally := ScrollIntoView(FFocusedColumn, Center); 

    end; 

    Result := ScrolledVertically or ScrolledHorizontally; 
end; 
+0

Возможный дубликат, см http://stackoverflow.com/questions/2839397/how-to-reliably-scroll-virtual-treeview-to-the-bottom –

+0

К сожалению, нет -/ –

+0

цель этого " если "ветвь очевидна: функция ScrollIntoView не предназначена для * только * прокрутки до последнего узла. Он предназначен для прокрутки на * любой * узел, включая узлы, которые находятся выше текущего видового экрана. –

ответ

0

Я думаю, время, чтобы использовать новые функции, такие как DELPHI класса помощники: р я написал что-то простое в моих Main.pas, кажется, работает, но я не уверен, что он будет охватывать все случаи.

TBaseVirtualTreeHelper = class helper for TBaseVirtualTree 
    public 
    Procedure ScrollToTheBottom(); 
    end; 

{ TBaseVirtualTreeHelper } 
procedure TBaseVirtualTreeHelper.ScrollToTheBottom; 
Var 
    Node: PVirtualNode; 
    R: TRect; 

begin 
    Node := Self.GetLast(); 

    if Assigned(Node) and (Node <> Self.FRoot) then 
    begin 
    R := GetDisplayRect(Node, NoColumn, True); 

    if (R.Bottom > Self.ClientHeight) then 
    begin 
     Self.SetOffsetY(Self.FOffsetY - R.Bottom + Self.ClientHeight); 
    end; 
    end; 
end; 
+1

Помощники класса здесь неактуальны. Ваша функция также может быть автономной функцией. Просто используйте свойства RootNode, OffsetX и 'OffsetY' вместо защищенных полей и методов. –

+0

Я этого не знал. Не могли бы вы привести пример? –

+0

Пример чего? –