Delphi RIO 10.3.1 FMX TListView 'ItemClickEx' запускает 2 для одного клика

Я пытаюсь реализовать функцию переключения при нажатии на элемент tlistview. Но при тестировании я замечаю, что событие щелчка запускается 2 раза одним щелчком/нажатием с ИДЕНТИЧНЫМИ параметрами. Сейчас я тестирую это на окнах. Это «работает так, как задумано»?

Я только добавил представление списка в пустую форму и реализовал событие «ItemClickEx».
Я не смог найти обходной путь для моего переключателя... кроме реализации таймер, который будет отслеживать клики и игнорировать второй клик в ближайшее время... (кажется, что структура FMX также работает с отложенными событиями при просмотре трассировки стека)

Я также протестировал событие onitemclick, и оно срабатывает только один раз. .. поэтому я, вероятно, мог бы использовать его для реализации простого обходного пути. Но нехорошо, мне нужна версия «ex», а также, в конечном итоге, мне нужно добавить/удалить элементы из моего списка, который рекомендуется только из версии «ex», согласно документации.

С уважением Дирк


person DDeberla    schedule 03.05.2020    source источник


Ответы (2)


Обновление См. раздел «Обновление» ниже, который основан на наблюдениях OP в его собственном ответе.

Минимальный проект ниже не демонстрирует поведение, которое вы описываете.

Если я щелкну любой элемент в ListView1, переменная ItemClickedCount увеличится только на единицу, что подтверждается отображением в заголовке формы (если я дважды щелкну форму, ItemClickedCount увеличится на 2, как и ожидалось).

Чтобы реализовать ваш переключатель, должно быть достаточно простого переключения логического значения, или вы можете просто получить состояние переключения из того, является ли ItemClickedCount нечетным или четным.

Итак, я думаю, что описанное вами поведение должно исходить из части вашего кода, не упомянутой в вашем вопросе. Очевидно, что способ определить причину — многократно упростить вашу форму и ее код. Удачи!

procedure TForm1.BuildList;
var
  LItem : TListViewItem;
  ListItemText : TListItemText;
  Index : Integer;
begin
  ListView1.BeginUpdate;
  try
    ListView1.Items.Clear;
    ListView1.ItemAppearanceObjects.ItemEditObjects.Text.TextVertAlign := TTextAlign.Leading;
    for Index := 0 to 19 do begin
      LItem := ListView1.Items.Add;
      LItem.ButtonText := 'Hello';
      LItem.Text := 'Row: ' + IntToStr(Index);
      LItem.Height := 25;
      ListItemText := TListItemText.Create(LItem);
      ListItemText.PlaceOffset.X := 100;
      ListItemText.PlaceOffset.Y := 25 * (Index - 1);
      ListItemText.Name := 'Name' + IntToStr(Index);
    end;
  finally
    ListView1.EndUpdate;
  end;
end;

procedure TForm1.ListView1ItemClickEx(const Sender: TObject; ItemIndex: Integer;
  const LocalClickPos: TPointF; const ItemObject: TListItemDrawable);
begin
  Inc(ItemClickedCount);
  Caption := IntToStr(ItemClickedCount);
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  BuildList;
end;

Обновление Отвечая на ваш комментарий + ответ, да, я вижу, что ListView1ItemClickEx вызывается дважды для каждого щелчка мыши. Я изучил, почему это происходит, и, похоже, это сделано преднамеренно, хотя почему так должно быть, для меня не очевидно.

Глядя на источник FMX.ListView (я делаю это в Сиэтле, поэтому ваши номера строк могут отличаться), ListView1ItemClickEx вызывается по строке 2003 (Case Entry.Incident of ... TDelayedIncident.ClickEvent:) в процедуре TListViewBase.ProcessIncident(const Запись: TDelayedIncidentEntry);

Очевидно, чтобы вызываться дважды, таких Incidents должно быть два на клик, поэтому я посмотрел, как эти Инциденты добавляются в любой обрабатываемый список/очередь. Затем я посмотрел на procedure TListViewBase.StartIncident(const Incident: TDelayedIncident; const Triggered: Boolean; const TimeToWait: Single; const CustomData: NativeInt); в строке 1949.

После каждого щелчка мыши это вызывается дважды:

  • В первый раз, глядя на стек вызовов, вызов исходит из procedure TListViewBase.SetNewItemIndex(const NewIndex: Integer) в строке 4083.

  • Второй раз изнутри procedure TListViewBase.MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Single).

Для меня не очевидно, как избежать этого с помощью настроек свойств TListView, но это может быть. Однако есть простой обходной путь, который можно включить в обработчик ListView1ItemClickEx:

procedure TForm1.ListView1ItemClickEx(const Sender: TObject; ItemIndex: Integer;
  const LocalClickPos: TPointF; const ItemObject: TListItemDrawable);
var
 LItem : TListViewITem ;
begin
  Inc(ItemClickedCount);
  if not Odd(ItemClickedCount) then
    Exit;

  Caption := IntToStr(ItemClickedCount);

  LITem := ListView1.Items[ItemIndex];
  LItem.Tag :=  LItem.Tag + 1 ;

  LItem.Text := LItem.Text +  ' ' + LItem.Tag.ToString + 'clicks';

end;

Мне интересно, как связать эту обработку дедупликации с классом интерпозера, который вы могли бы включить в свой исходный модуль. Если я смогу придумать чистый способ, я, возможно, добавлю его сюда позже.

person MartynA    schedule 03.05.2020
comment
Привет, я проверил, пожалуйста, смотрите мои выводы ниже - person DDeberla; 04.05.2020
comment
Привет, спасибо за подтверждение этого! Это всегда помогает оценить собственный уровень здравомыслия :-). Обходной путь на месте. Я действительно думаю, что это должно быть классифицировано как «ошибка». Наличие нескольких событий может быть приемлемым (из-за нескольких подкомпонентов в элементе, но не с одинаковыми параметрами). 1 клик - это 1 клик, с уважением. - person DDeberla; 05.05.2020


Спасибо за ваш вклад.

Вы правы, если вы только добавите TListview и заполните его TListviewitems в коде и оставите внешний вид элемента по умолчанию как ListItem, событие сработает только один раз и в моей настройке.
Однако, как только я изменю ItemAppearance на ' custom» и, кроме того, сделать видимой только кнопку Glyphbutton, она срабатывает 2 раза.
Кажется, это не зависит от того, перекрываются ли фактические объекты элементов (текст, глиф, аксессуар) или нет (поэтому дело не в том, что, например, событие нажатия кнопки глифа также передается еще раз в событие щелчка элемента)
Это также не важно, где именно я нажимаю, он всегда срабатывает 2 раза

Вы видите такое же поведение?

type
  TForm1 = class(TForm)
    Panel1: TPanel;
    Button1: TButton;
    ListView1: TListView;
    procedure Button1Click(Sender: TObject);
    procedure ListView1ItemClickEx(const Sender: TObject; ItemIndex: Integer;
      const LocalClickPos: TPointF; const ItemObject: TListItemDrawable);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

procedure TForm1.Button1Click(Sender: TObject);
var
 i : integer ;
 LItem : TListViewItem ;

 lListView : TListView ;
begin


  // Here we should create the overal listview structure
  // The visual appearance of items need to be done in updateobjects
  // Only this one is always (re)triggered !!

  lListView := ListView1;
  lListView.BeginUpdate;
  try
   for i := 0 to 10 - 1 do begin
     LItem := lListView.Items.Insert(i);
     LItem.Text := 'Test' + I.ToString;
   end;
  finally
    lListView.EndUpdate;
  end;


end;

procedure TForm1.ListView1ItemClickEx(const Sender: TObject; ItemIndex: Integer;
  const LocalClickPos: TPointF; const ItemObject: TListItemDrawable);
var
 LItem : TListViewITem ;
begin

LITem := ListView1.Items[ItemIndex];
LItem.Tag :=  LItem.Tag + 1 ;

LItem.Text := LItem.Text +  ' ' + LItem.Tag.ToString + 'clicks';

end;

...

  object ListView1: TListView
    ItemAppearanceClassName = 'TCustomizeItemObjects'
    ItemEditAppearanceClassName = 'TCustomizeItemObjects'
    HeaderAppearanceClassName = 'TListHeaderObjects'
    FooterAppearanceClassName = 'TListHeaderObjects'
    Align = Client
    Size.Width = 640.000000000000000000
    Size.Height = 439.000000000000000000
    Size.PlatformDefault = False
    TabOrder = 1
    ItemAppearanceObjects.ItemObjects.Text.Width = 100.000000000000000000
    ItemAppearanceObjects.ItemObjects.Text.Height = 44.000000000000000000
    ItemAppearanceObjects.ItemObjects.Text.PlaceOffset.X = 168.000000000000000000
    ItemAppearanceObjects.ItemObjects.Detail.Width = 230.000000000000000000
    ItemAppearanceObjects.ItemObjects.Detail.Height = 44.000000000000000000
    ItemAppearanceObjects.ItemObjects.Detail.PlaceOffset.X = 230.000000000000000000
    ItemAppearanceObjects.ItemObjects.Accessory.Visible = True
    ItemAppearanceObjects.ItemObjects.GlyphButton.Width = 31.000000000000000000
    ItemAppearanceObjects.ItemObjects.GlyphButton.Height = 30.000000000000000000
    ItemAppearanceObjects.ItemObjects.GlyphButton.Visible = True
    ItemAppearanceObjects.ItemObjects.GlyphButton.PlaceOffset.X = 24.000000000000000000
    OnItemClickEx = ListView1ItemClickEx
  end

с уважением Дирк

person DDeberla    schedule 04.05.2020