delphi ScrollBox Для большого кол-ва элементов

Рейтинг: 0Ответов: 0Опубликовано: 09.01.2023

Мне нужно придумать алгоритм определения индекса элемента в списке scrollbox по позиции. Основная проблема это оптимизация из-за большого кол-ва элементов в scrollbox. Если использовать все стандартное то лаги дикие при прокрутке.

Суть.

1.scrollbox мой собственный поэтому все переменные кастомные и с комментами.

  1. в scrollbox может быть очень много элементом. 1 млм к примеру.

  2. в scrollbox есть 2 типа элементов

    1. то что видно далее SHOW

    2. то что не видно (их как правило большинство) далее HIDE это просто TObject с своими полями

  3. Достаточно создать 4 - 10 SHOW что бы отобразить 1 млм HIDE

  4. У каждого HIDE есть своя ширина высота которая не одинакова

    (если бы она была одинакова то этого вопроса бы не было,

    т.к год назад написал похожий алгоритм для const Высоты элемента

    он прекрасно работает)

Проблема При прокрутке списка нужно определить Index HIDE в списке LISTHIDE по новой позиции C Наименьшим кол-во итераций. Проблема позанного алгоритма это перебор всех значений при каждом движении скрола и чем дальше итем в списке тем дольше цикл будет работать

function TPtoBox.HideIndexAtPositionGet(ANewPosition:integer;var OffsetShowScroll:integer):integer;
var i,ARange,h:integer;
begin
   OffsetShowScroll:=0; 
   ARange:=0;
   Result:=-1;
   for I := 0 to FListHide.Count-1 do
    begin
       h:=FListHide.ItemsBaza[i].HeightSave;
       if (ARange <= ANewPosition) and (ARange + h >= ANewPosition)  then
       begin
          Result:=  i;
          OffsetShowScroll:=  -(ANewPosition - ARange);
          break;
       end;
       inc(ARange,h);
    end;

Бинарный поиск не подойдет т.к мы не знаем позицию относительно начала LISTHIDE каждого HIDE а считать ее обратно цикл перебора вызывать нужно.

==================================================================== Я пришел пока к тому что нужно сохранять в переменную позицию HIDE тогда меньше проблем и итераций но как эту позицию для каждого HIDE потом обновлять - обратно цикл перебора вызывать - (отчего ушли к тому же и пришли)

Теперь алгоритм поиска такой. Но проблема как обновить TOPMUST для каждого HIDE если скажем высота одного SHOW поменялась

function TPtoBox.BazaIndexAtPositionGet(var APosition:integer;var Offset:integer):integer;
var i,r,h,bt,bb,APositionScroll:integer;

    function LocGetIndex(IndexBegin,IndexEnd:integer):integer;
    var Bool:Boolean;
        AOffset:integer;
    begin
            AOffset:= Offset;
          Bool:=AmSerchBase.BinaryOf(Result,IndexBegin,IndexEnd,
            function(ind:integer):real
            var p,p2:real;
            PosTop,PosBottom:Int64;
            var ABazaItem:TPtoBaza;
            begin
              ABazaItem:=   FListBaza.ItemsBaza[ind];
              PosTop:=ABazaItem.FTopMost;
              PosBottom:=  PosTop + ABazaItem.Height;
              if (PosTop <= APositionScroll) and (PosBottom >= APositionScroll) then
              begin
                Result:=0;
                AOffset:=  -(APositionScroll - PosTop);
              end
              else if PosTop >  APositionScroll  then  Result:=1
              else Result:=-1;
            end);
            Offset:= AOffset;
            if not Bool then Result:=-1;
    end;
    var Now,Pred:TPtoBaza;
begin

    Result:=-1;
    if APosition<0 then
    APosition:=0;
    Offset:=0;
    if APosition>BazaRangeClient then
    APosition:=  BazaRangeClient;
    if APosition<0 then
    APosition:=0;
    r:=0;
    APositionScroll:=  APosition;

        bt:=BazaIndexTop;
        if bt>0 then
        begin
            Pred:= FListBaza.ItemsBaza[bt-1];
            r:=  Pred.FTopMost + Pred.Height ; //FTopMost не верные данные
        end;
        if ( APosition < r  ) and (bt>0) then
        begin
            Result:=LocGetIndex(0,bt-1);
            if Result>=0 then exit;
        end
        else
        begin
            bb:= BazaIndexBottom;
            if bb<FListBaza.Count-1 then
            begin
                Pred:= FListBaza.ItemsBaza[bb+1];
                if ( APosition >= self.ChildrenScrollRangeVert + Pred.FTopMost) then
                begin
                    APositionScroll:= APositionScroll - self.ChildrenScrollRangeVert;
                    Result:=LocGetIndex(bb+1,FListBaza.Count-1);
                    if Result>=0 then exit;
                end;
            end;

        end;



    for I := 0 to self.ChildrenCount-1 do
    if TPtoPanel(Childrens[i]).Baza<>nil then
    begin
       h:=TPtoPanel(Childrens[i]).Baza.Index;
       h:= TPtoPanel(Childrens[i]).Height + AmScaleV(self.ChildrenAlign.BolderVert);
       if (r <= APosition) and (r + h >= APosition)  then
       begin
          Result:=  TPtoPanel(Childrens[i]).Baza.Index;
          Offset:=  -(APosition - r);
          break;
       end;
       inc(r,h);
    end;

end;

Ответы

Ответов пока нет.