TVirtualStringTree: прокрутка вниз до двух приводит к переключению

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

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

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

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

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;

1 ответ

Я предполагаю, что пришло время использовать новые функции Delphi, такие как помощники классов:p Я написал что-то простое в своем файле 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;
Другие вопросы по тегам