Перейти к содержанию
Fire Monkey от А до Я
  • 0

OnUpdateObjects OnUpdatingObjects в Берлине


krapotkin

Вопрос

В Сиеттле было все довольно логично

Ставлю режим ItemAppearance=Custom, ставлю все родные компоненты Visible=False и в OnUpdateObjects создаю все что мне нужно.

Алгоритм был такой:

NewItem := listView.items.Add(); // тут срабатывает OnUpdateItems и создается MyListItemControl
c:=NewItem.Objects.FindDrawable('MyControl') as TMyControl;
if c<>NIL then 
  c.Text := 'Item '+IntToStr(i);

в Берлине OnUpdateItems срабатывает совсем потом. И в режиме Dynamic и в Custom

в результате с=NIL; O_O

и сейчас я не понимаю, как теперь я должен заполнять Items своими компонентами

Ссылка на комментарий

Рекомендуемые сообщения

  • 0

Короче, нащупал линию поведения.

поместил код в OnUpdatingObjects и поставил AHandled:=True;

Срабатывает он теперь не при Items.Add, а при первом обращении к Item.Objects !

Будьте внимательны

P.S. ItemAppearance можно ставить любой

Ссылка на комментарий
  • 0

разочаровался во встроенных объектах, теперь все объекты list item создаю сам. зато полный контроль, что когда создано...

сделал себе дополнительные классы TListItemCircle, TListItemRect, TListItemLine и даже TListItemTri - треугольную меточку в угол итема. Вроде закрыл все свои потребности, в том числе в закрашивании итема.

Есть проблемка.

Чтобы все нормально работало в ListView.OnClickItemEx нужно задавать каждому элементу конкретные размеры. Если элементы пересекаются, клик детектируется на первом по времени создания.

Но тогда, если подставлять цветной прямоугольник под весь итем, то все клики упадут на него!

Надо думать...

Ссылка на комментарий
  • 0
В 07.06.2016 в 14:48, krapotkin сказал:

в Берлине OnUpdateItems срабатывает совсем потом. И в режиме Dynamic и в Custom

Сегодня, в совсем еще недавно хорошо работающем проекте, заметил такое же поведение... При Item.Add код срабатывает только при первом обращении корректно. При последующих работает совершенно неадекватно, пока не изменишь размеры окна, например... (чтобы ListView перерисовался)

С чем это связано вообще не понятно. Проект никак не изменял в плане подсчета высоты Итемов, ничего не переделывал. Добавил пару кнопок и пару функций.

В 07.06.2016 в 16:25, krapotkin сказал:

поместил код в OnUpdatingObjects и поставил AHandled:=True;

Попытался проделать то же самое, программа вылетает (код тот же самый, что и в моей соседней теме - автоподсчет высоты Итема).

Начинаю потихоньку ненавидеть Берлин :)

 

Сегодня попробовал на пустом проекте - все перерисовывается как надо. Пересчет идет корректно.

На старом проекте не работает. Куда копать кто-нибудь знает?

Изменено пользователем HyperZen
Ссылка на комментарий
  • 0

я еще раз в этой теме приложу тестовый проект полностью рабочий под берлин с ресайзом

ListViewTestBerlin.7z

Ссылка на комментарий
  • 0
3 часа назад, krapotkin сказал:

я еще раз в этой теме приложу тестовый проект полностью рабочий под берлин с ресайзом

Огромное спасибо за пример!

Просто это, видимо, глюк Берлина. Ведь на пустом новом проекте все работает адекватно! И без всяких дополнительных ресайзов.

На старом проекте пришлось брать в руки бубен.

Ссылка на комментарий
  • 0
В 10.06.2016 в 17:46, HyperZen сказал:

Просто это, видимо, глюк Берлина. Ведь на пустом новом проекте все работает адекватно! И без всяких дополнительных ресайзов.

На старом проекте пришлось брать в руки бубен.

Добрый вечер :)

HyperZen, правильно ли понимаю: если снести LV, мигрированный из более ранней версии Delphi, то все Item.Add отрабатывают корректно?

У меня та же ерунда. Экспериментировать не берусь пока - слишком много нагромождено, времени много уйдет. Обошелся Вашим советом (костыль с resize), но чую, что где-нибудь "старый" LV может выкинуть неожиданный финт...

В 10.06.2016 в 14:53, krapotkin сказал:

я еще раз в этой теме приложу тестовый проект полностью рабочий под берлин с ресайзом

ListViewTestBerlin.7z

За пример и разжевывание спасибо огромное! Выручили! Вот только заметил такую "Болезнь": если на форму поставить кнопку и по ней перерисовать все, возникнет баг с расчетом высоты... :(

Пугает меня скрытыми неожиданностями Берлин :(

 

Ссылка на комментарий
  • 0

баг с расчетом чаще всего значит, что ширина задана неправильно

оно же по ширине раскладывает

но есть и нормальный баг, когда стиль применяется только к видимым (или наоборот- невидимым, не помню уже) айтемам

Ссылка на комментарий
  • 0
18 часов назад, ra.eremeev сказал:

Добрый вечер :)

HyperZen, правильно ли понимаю: если снести LV, мигрированный из более ранней версии Delphi, то все Item.Add отрабатывают корректно?

У меня та же ерунда. Экспериментировать не берусь пока - слишком много нагромождено, времени много уйдет. Обошелся Вашим советом (костыль с resize), но чую, что где-нибудь "старый" LV может выкинуть неожиданный финт...

Нет. Как только я ни бился с расчетом высоты итемов компонента ListView... Ничего не помогало, пока я не понял, что все ошибки связаны с размером шрифта по-умолчанию, установленного в конкретном устройстве. Обошел эту проблему, теперь все работает корректно на любых (ЛЮБЫХ) устройствах!

Для этого при расчете высоты итема прибавляю к размеру шрифта 0.1 и все расчет ведутся корректно. А процедуру расчета взял на этом замечательном форуме.

Ссылка на комментарий
  • 0

Большое спасибо за помощь!

Разобрался с новым LV. Теперь радости нет предела. По мне, работать с ним стало проще. Пусть теперь приходится создавать все компоненты вручную, но, зато полный контроль и отображение без фокусов :)

Со старым LV были свои заморочки.

Остался один вопрос: никак не могу разобраться с загрузкой в итем картинок с веб-сервера. Картинки в итемы грузятся в потоках.

Процедура загрузки работает корректно - проверено.

TListItemImage создаю в OnUpdatingObjects. Но как раньше, в OnPaint не получается в него грузить картинку - выдает ошибку.

Как понял, элемент становится доступным после OnPaint.

Но и загрузка в OnUpdateObjects отрабатывает некорректно.

Есть ли опыт? Буду признателен, если поделитесь...

 

Ссылка на комментарий
  • 0

про потоки. на всякий случай

тут неоднократно отмечалось, что работа с TBitmap может быть только в Synchronize. и где-то был демо код с асинхронной загрузкой картинок

Скорее всего, у @ZuBy

Ссылка на комментарий
  • 0
1 час назад, krapotkin сказал:

тут неоднократно отмечалось, что работа с TBitmap может быть только в Synchronize. и где-то был демо код с асинхронной загрузкой картинок

Да, я тоже по этому принципу загрузку в потоках изображения строю.

Но вопрос в событии, в котором запускать эту отрисовку.

Раньше делал старт потока в OnPaint, теперь так не проходит :(

Ссылка на комментарий
  • 0

по идее, после скролла OnScrollViewChange я бы проверял, во всех ли видимых итемах есть картинки, и не нужно ли поудалять их в невидимых

Ссылка на комментарий
  • 0

Берлин апдейт 2, Андроид. Сделал в своем приложении все по примеру уважаемого krapotkin. Но получил адовый писец. Для смеха записал видео:

http://www.kayfolom.ru/2017_02_28_09_41_47.mp4

Кнопка Refresh, в правом-верхнем углу, на самом деле выполняет Resize для ListView.

ListView заполняется данными из нескольких json полученных с сервера, получается последовательное добавление секций. Вот пример заполнения одной из секций:

procedure TFormMain.FillUserBalance(AJSON : TJSONObject);
Var JSONValue : TJSONValue;
    I : Integer;
    AName, AValue : String;
    AItem : TListViewItem;
begin
  if Not AJSON.TryGetValue('getuserbalance', JSONValue) then
    Exit;
  if Not JSONValue.TryGetValue('data', JSONValue) then
    Exit;
  AJSON:=JSONValue as TJSONObject;
  if Not Assigned(AJSON) then
    Exit;
  ListView.Items.Clear;
  AItem:=ListView.Items.Add;
  AItem.Purpose:=TListItemPurpose.Header;
  AItem.Text:='Balance ' + Setting.CurrentPool.Pool.Coin;
  for i := 0 to AJSON.Count-1 do
  begin
    AName:=AJSON.Pairs[I].JsonString.Value;
    if AJSON.TryGetValue(AName, JSONValue) Then
    begin
      FListViewUpdating:=True;
      AItem:=ListView.Items.Add;
      AItem.Data['Type']:='balance';
      AItem.Data['Name']:=AName;
      AValue:=JSONValue.Value;
      AItem.Data['Value']:=AValue;
      FListViewUpdating:=False;
      AItem.Adapter.ResetView(AItem);
    end;
  end;
end;

Создаю drawable в ListViewUpdatingObjects:

procedure TFormMain.ListViewUpdatingObjects(const Sender: TObject;
  const AItem: TListViewItem; var AHandled: Boolean);
Var AName, AValue, ADateAndTypeTransaction, AAmount, ATransactionOther, APaymentType  : TListItemText;
    AvailableWidth : single;
    AItemHeight : single;
    AItemType, ATransactionOtherString : String;
    S : String;
  function SetupTextObject(const AName, AText : String; AWidth, AHeight, X , Y : Single;
      AAlign, AVertAlign: TListItemAlign; ATextAlign, ATextVertAlign: TTextAlign) : TListItemText;
  begin
    Result:=TListItemText(AItem.View.FindDrawable(AName));
    if Result=Nil then
      Result:=TListItemText.Create(AItem);
    Result.Name:=AName;
    Result.Width:=AWidth;
    Result.Text:=AText;
    Result.PlaceOffset.X:=X;
    Result.PlaceOffset.Y:=Y;
    Result.Align:=AAlign;
    Result.VertAlign:=AVertAlign;
    Result.TextAlign:=ATextAlign;
    Result.TextVertAlign:=ATextVertAlign;
    if AHeight=-1 then
//      Result.Height:=CalculateHeight(Result, Sender as TListView, FTextLayout)
      Result.Height:=GetTextHeight(Result, AWidth, AText)
    else
      Result.Height:=AHeight;
//    Result.Visible:=True;
  end;
begin
  if FListViewUpdating then  Exit;
  AvailableWidth:=TListView(Sender).Width - TListView(Sender).ItemSpaces.Left - TListView(Sender).ItemSpaces.Right;

  AItemType:=AItem.Data['Type'].AsString;
  if AItem.Purpose=TListItemPurpose.None Then
  begin
    if AItemType.Equals('balance') or AItemType.Equals('hashrate') or AItemType.Equals('worker')then
    begin
      AName:=SetupTextObject('Name', AItem.Data['Name'].AsString, AvailableWidth, -1, 0, 0,
        TListItemAlign.Leading, TListItemAlign.Leading, TTextAlign.Leading, TTextAlign.Leading);
      AItemHeight:=AName.Height;
      if AItem.Data['Type'].AsString='worker' then
      begin
        if AItem.Data['Value'].AsString.Equals('0') Then
          AName.TextColor:=TAlphaColorRec.Red
        else
          AName.TextColor:=TAlphaColorRec.Green;
      end;
      AValue:=SetupTextObject('Value', AItem.Data['Value'].AsString, AvailableWidth, -1, 0, 0,
        TListItemAlign.Trailing, TListItemAlign.Leading, TTextAlign.Trailing, TTextAlign.Leading);
      AItem.Height:=Round(AItemHeight + (Sender as TListView).ItemSpaces.Top +
        (Sender as TListView).ItemSpaces.Bottom);
    end;

    if AItem.Data['Type'].AsString='Transaction' then
    begin
      ADateAndTypeTransaction:=SetupTextObject('DateAndTypeTransaction',
        AItem.Data['Date'].AsString + ' ' + AItem.Data['TransactionType'].AsString,
        AvailableWidth, -1, 0, 0,
        TListItemAlign.Leading, TListItemAlign.Leading, TTextAlign.Leading, TTextAlign.Leading);

      AItemHeight:=ADateAndTypeTransaction.Height;

      AAmount:=SetupTextObject('Amount',
        AItem.Data['Amount'].AsString,
        AvailableWidth, -1, 0, 0,
        TListItemAlign.Trailing, TListItemAlign.Leading, TTextAlign.Trailing, TTextAlign.Leading);

      ATransactionOtherString:='';
      if Not AItem.Data['AmountFee'].AsString.IsEmpty then
        ATransactionOtherString:=ATransactionOtherString + 'Fee ' + AItem.Data['AmountFee'].AsString + ' ';
      if Not AItem.Data['AmountDonation'].AsString.IsEmpty then
        ATransactionOtherString:=ATransactionOtherString + 'Donat ' + AItem.Data['AmountDonation'].AsString + ' ';
      if Not AItem.Data['Confirmations'].AsString.IsEmpty then
        ATransactionOtherString:=ATransactionOtherString + 'Confirm ' + AItem.Data['Confirmations'].AsString;

      ATransactionOther:=SetupTextObject('TransactionOther', ATransactionOtherString,
        AvailableWidth, -1, 0, AItemHeight,
        TListItemAlign.Leading, TListItemAlign.Leading, TTextAlign.Leading, TTextAlign.Leading);

      AItem.Height:=Round(AItemHeight + ATransactionOther.Height +
        (Sender as TListView).ItemSpaces.Top + (Sender as TListView).ItemSpaces.Bottom);
      S:=AItem.Data['TransactionType'].AsString;
      if AItem.Data['TransactionType'].AsString.Contains('Debit') then
        AAmount.TextColor:=TAlphaColorRec.Blue;
      if AItem.Data['TransactionType'].AsString.Contains('Credit') then
        AAmount.TextColor:=TAlphaColorRec.Green;
    end;
    AHandled:=True;
  end;
end;

В итоге: все работает на порядок медленнее чем вариант с созданием drawable сразу, при заполнении данных. Для нормального подсчета высоты итемов помогает только Resize, и то только для видимых итемов.

Под виндой все работает хорошо. Под андроид так как на видео.

Ссылка на комментарий
  • 0
  • Модераторы

я уже стараюсь отойти от создания вручную объектов, есть же DynamicAppearance, все прекрасно работает и все шустро, никаких ресайзов не нужно делать

Ссылка на комментарий
  • 0
1 час назад, Равиль Зарипов (ZuBy) сказал:

я уже стараюсь отойти от создания вручную объектов, есть же DynamicAppearance, все прекрасно работает и все шустро, никаких ресайзов не нужно делать

У меня как раз DynamicAppearance, но в одном ListView должны быть разные итемы, вверху все просто Ключ-Значение, в транзакциях будут многострочные данные с разным цветом, зачеркиванием  и т.д.

В этом случае без динамического создания не обойтись. Если бы дизайнер ListView умел делать несколько моделей итема, было бы хорошо. Но мечты-мечты...

Ссылка на комментарий
  • 0

Я наступил на те же грабли что и уважаемый HyperZen. Причем наступал я на эти грабли много раз раз, в каждой версии Delphi.

Малюсенькое исправление решает проблему:

  function SetupTextObject(const AName, AText : String; AWidth, AHeight, X , Y : Single;
      AAlign, AVertAlign: TListItemAlign; ATextAlign, ATextVertAlign: TTextAlign) : TListItemText;
  begin
    Result:=TListItemText(AItem.View.FindDrawable(AName));
    if Result=Nil then
    begin
      Result:=TListItemText.Create(AItem);
    Result.Name:=AName;
    Result.Width:=AWidth;
	//*********************************************************
    Result.Font.Size:=Result.Font.Size + 0.01; // Вот этот костыль заставляет все работать как задуманно.
	//*********************************************************
    Result.Text:=AText;
    Result.PlaceOffset.X:=X;
    Result.PlaceOffset.Y:=Y;
    Result.Align:=AAlign;
    Result.VertAlign:=AVertAlign;
    Result.TextAlign:=ATextAlign;
    Result.TextVertAlign:=ATextVertAlign;
    if AHeight=-1 then
    begin
      if FListViewItemTextHeigh=-1 then // Так как везде один шрифт, то вычисляем высоту текста однократно
      begin
        FListViewItemTextHeigh:=GetTextHeight(Result, AWidth, AText);
        Result.Height:=FListViewItemTextHeigh;
      end
      else
        Result.Height:=FListViewItemTextHeigh;
    end
    else
      Result.Height:=AHeight;    
    end;
  end;

Проблема в старинном глюке эмбаркадеровского ListView - вычисление высоты текста на этапе создания, или позднее не имеет смысла, потому как размер шрифта по умолчанию (обычно 12), перед отрисовкой превратиться во все что угодно, но не в 12, стиль применит свой размер шрифта и ваши расчеты высоты итема можно будет выкинуть. Победить глюк можно только установкой своего размера (обязательно отличного от 12 - цифра 12 "мудро" используется ембаркадерой как флаг означающий что можно применить стиль.

Помню что задавал здесь этот вопрос не раз, но так и не получил ответа - как узнать размер шрифта из стиля, а не из FontSize????????????????!!!!!!!!!!!!!! Только с размерами шрифта из стиля имеет смысл расчитывать высоту.

Даже в стандартых примерах эмбаркадыры этот скользкий момент старательно обходится и внимание на нем не концентрируется. Вот пример \Studio\18.0\Samples\Object Pascal\Multi-Device Samples\User Interface\ListView\VariableHeightItems:

    Drawable.Font.Size := 1; // Ensure that default font sizes do not play against us
    Drawable.Font.Size := 10 + Random(4) * 4;

они делают хитро, вместо стандартный 12 пишут 1, а потом уже вписывают нужные значения. Если закомментировать эти две строчки (или написать Drawable.Font.Size := 12), то пример перестает работать, текст режется.

Ссылка на комментарий
  • 0

Похоже я все победил! Вот код который отлично работает без костылей:

  function SetupTextObject(const AName, AText : String; AWidth, AHeight, X , Y : Single;
      AAlign, AVertAlign: TListItemAlign; ATextAlign, ATextVertAlign: TTextAlign) : TListItemText;
  begin
    Result:=TListItemText(AItem.View.FindDrawable(AName));
    if Result=Nil then
    begin
      Result:=TListItemText.Create(AItem);
    Result.Name:=AName;
    Result.Width:=AWidth;
    Result.Text:=AText;
    Result.PlaceOffset.X:=X;
    Result.PlaceOffset.Y:=Y;
    Result.Align:=AAlign;
    Result.VertAlign:=AVertAlign;
    Result.TextAlign:=ATextAlign;
    Result.TextVertAlign:=ATextVertAlign;
    if AHeight=-1 then
    begin
      if FListViewItemTextHeigh=-1 then
      begin
        // Ищем стилевой объект 'font' в ListView и присобачиваем его к нашему итему
        AFontObject:=(AListView.FindStyleResource('font') as TFontObject);
        if Assigned(AFontObject) then
          Result.Font.Assign(AFontObject.Font);
        FListViewItemTextHeigh:=GetTextHeight(Result, AWidth, AText);
        Result.Height:=FListViewItemTextHeigh;
      end
      else
        Result.Height:=FListViewItemTextHeigh;
    end
    else
      Result.Height:=AHeight;
    Result.Visible:=True;
    end;
  end;

До применения шрифта из стиля Result.Font.Size=12, после Result.Font.Assign(AFontObject.Font) значение размера меняется на 18 - теперь высота рассчитывается корректно.

Ссылка на комментарий

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить на вопрос...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

  • Последние посетители   0 пользователей онлайн

    • Ни одного зарегистрированного пользователя не просматривает данную страницу
×
×
  • Создать...