Страница 1 из 1

Особенности TListView, TTreeView

СообщениеДобавлено: 20.06.2022 01:52:15
Sharfik
Маленький прикол, как не надо работать с компонентами для новичков.
Компоненты TListView, TTreeView прекрасны тем, что с ними можно быстро слепить прототип какого то решения задачи. В добавок в них есть реализация собственной отрисовки внешнего вида, которая позволяет подстраивать их под нужды проекта. Некоторые процедуры не работают, если не включить их соответствующей опцией, переориентировав на работу по другой логике. Но есть и такие, которые работают всегда. И иногда позволяют творить магию.
Вот представьте, программа компилируется, все отрабатывает почти идеально. И в какой то момент развития добавив функционал оказывается что TAction не обрабатывает события Update. Странное дело, наверно разработчики FPC не до конца допилили ядро, и через кучу друг в друга вложенных форм, панелек и т.д. не проходит оповещение. Но вот не задача, есть InputQuery, который появляется, но не закрывается при нажатии на его кнопки. Совсем.
Тут можно долго биться головой о стену, доказывая что они идиоты, но на самом деле причина багов в CustomDrawItem класса TListView. Скажем так, если сделать такой код

Код: Выделить всё
procedure TFReport.lvProjectCustomDrawItem(Sender: TCustomListView;
         Item: TListItem; State: TCustomDrawState; var DefaultDraw: Boolean);
var
  rlItem :TReportLogItem;
begin
if Assigned(Item) and Assigned(Item.Data) then
begin
      rlItem:=TReportLogItem(Item.Data);

      if (DateUtils.DateTimeToUnix(rlItem.CreateDate)+10)>DateUtils.DateTimeToUnix(now) then
      begin
          (Sender as tlistview).Canvas.Brush.Color := $00FAFFEC;
      end;
end;
end;

тот тут нет ничего плохого, но вот если вместо него окажется что то вроде
Код: Выделить всё
procedure TFCableLayingEditor.lvSubItemsCustomDrawItem(Sender: TCustomListView;
  Item: TListItem; State: TCustomDrawState; var DefaultDraw: Boolean);
var
  TmpItem:TAssiBasicObjectItem;
begin
  if Assigned(Item.Data) then
  begin
    TmpItem                  :=TAssiBasicObjectItem(Item.Data);
    Item.Caption             :=TmpItem.GetParameter('LabelName');
    Item.SubItems.Strings[0] :='';
    Item.SubItems.Strings[1] :=FloatToStr(TmpItem.GetParameter('Count'));
  end;
end;   

то программа будет работать, медленнее чем может, но будет. И это будет продолжаться до того момента, пока код не разрастется и не перестанет выполнять простые InputQuery.
К сожалению, для обновления на лету ListView нужно использовать либо OwnerData и соответствующую процедуру. Что не очень удобно, либо писать отдельные процедуры завязанные на какие то тригеры, чтобы обновлять все ручками. Попытка обновления содержимого во время рисования вызовет повторное рисование, и в какой то момент внутри системы срабатывает "бан" на происходящее. И хромая собака вовыляет на монитор. :roll:

Re: Особенности TListView, TTreeView

СообщениеДобавлено: 20.06.2022 21:10:12
Alex2013
Я тут недавно пилил галерею на TListView
Изображение
И там что-бы нарисовать рамку выделения текущего элемента нужным цветом пришлось "копать глубины".
Заработало как-то так ...
Код: Выделить всё
procedure TForm1.ListView1AdvancedCustomDrawItem(Sender: TCustomListView;
  Item: TListItem; State: TCustomDrawState; Stage: TCustomDrawStage;
  var DefaultDraw: Boolean);
  Var  A_Rect: TRect;
begin
case (Stage) of
  cdPrePaint  : begin
    if cdsSelected in State then
    with Sender.Canvas do begin
     Item.Selected := False;
     font.Color:= clWhite;
     Brush.Color := clRed;
     Pen.Color:=ClGreen;
    end;
  end;
  cdPostPaint : begin
    if cdsSelected in State then
    with Sender.Canvas do begin
      Item.Selected := True;
     A_Rect:=Item.DisplayRect(drSelectBounds);
        Pen.Color:=ClRed;
        Pen.Width:=2;
        Brush.Color :=ClGreen;

     Frame(A_Rect.Left+1,A_Rect.Top+1,
          A_Rect.Right-1,A_Rect.Bottom);

     Brush.Color := clWindow;
     Pen.Color:=  clWindow;
    end;
  end;
end;
end;

Суть прикола в том что без проверки поля Stage и использования AdvancedCustomDrawItem ничего путного не выходит . :idea:

Re: Особенности TListView, TTreeView

СообщениеДобавлено: 20.06.2022 23:06:28
Sharfik
А можно нескромно спросить почему не VirtualStringTree?
Работа конечно колосальная. Наверно если работать в cdPrePaint все равно писать обратно в переменные хранилища не стоит.

Re: Особенности TListView, TTreeView

СообщениеДобавлено: 21.06.2022 12:32:05
Alex2013
VirtualTree штука классная но иногда ее использование это ИМХО "из пушки по воробьям" .
Sharfik писал(а): Наверно если работать в cdPrePaint все равно писать обратно в переменные хранилища не стоит.

Почему ? :roll: Там-же вроде как есть блокировка :idea:
Код: Выделить всё
ListView1.BeginUpdate;
//(тут что-то меняем)
ListView1.EndUpdate;

Re: Особенности TListView, TTreeView

СообщениеДобавлено: 23.06.2022 01:11:49
Sharfik
Alex2013 писал(а):Почему ? Там-же вроде как есть блокировка

Делать блокировку в процедуре самоотрисовки? Думаешь хорошая идея?

Re: Особенности TListView, TTreeView

СообщениеДобавлено: 04.07.2022 11:34:00
Alex2013
Sharfik писал(а):Делать блокировку в процедуре самоотрисовки? Думаешь хорошая идея?

Разумеется , если ты блокируешь "чужую отрисовку" то это какая никакая гарантия что не будет зацикливания и "кольцевания" (тоже самое но чуть под другим соусом ) алгоритма . (Иначе получится примерно так : изменение полей данных вызывает отрисовку , которая вызывает изменение полей данных, а изменение полей данных снова вызывает отрисовку и т.д. и т.п. до полного забивания стека )