• 0
Belov.V.

После активации TSearchBox не возвращается индекс нового добавленого элемента

Вопросы

Столкнулся с такой ситуацией.
 
1) Заполняем TListBox;
2) Пользуемся поиском через TSearchBox;
3) Очищаем TSearchBox;
4) При попытке добавить любой новый элемент в TListBox, всегда возвращается индекс добавленного элемента "-1".
 
Накидал пример для экспериментов, упростив до безобразия (прикрепляю).
 
Как восстановить возможность получать индекс добавленного элемента?
 

0_116754_6fc8cf12_orig.png

Project1.zip

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

9 ответов на этот вопрос

  • 0

К сожалению этот вопрос до сих пор не имеет однозначного ответа.

А вопрос такой, какой индекс итема должен вернуться?

  1. Индекс в отфильтрованном списке
  2. или индекс в исходном?

В текущей реализации возвращается индекс в отфильтрованном списке. Поэтому если добавляемый итем не попадает под условие фильтра, то функция возвращает -1. А если попадет, то она вернет индекс в отфильтрованном списке.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
  • 0

К сожалению этот вопрос до сих пор не имеет однозначного ответа.

А вопрос такой, какой индекс итема должен вернуться?

  1. Индекс в отфильтрованном списке
  2. или индекс в исходном?

В текущей реализации возвращается индекс в отфильтрованном списке. Поэтому если добавляемый итем не попадает под условие фильтра, то функция возвращает -1. А если попадет, то она вернет индекс в отфильтрованном списке.

 

Индекс в отфильтрованном не возвращает ни в каком варианте.

 

- Если список не упорядочен (ListBox1.Sorted:=False), то возвращается индекс последнего добавленного по порядку (0,1,2,3 и т.д.). Из вопроса выше - 2-й вариант.

- Если список упорядочить (ListBox1.Sorted:=True), по возвращается индекс в упорядоченном списке. Тут вроде все корректно работает.

Но это варианты с сортировкой.

 

Если же мы устанавливаем значение TSearchBox, который действительно в данном случае выступает как фильтр, то при добавлении нового итема, вне зависимости от того попадает в фильтр или нет, всегда получаем "-1". В общем-то для упрощения я указал в п.3 (Очищаем TSearchBox). При пустом фильтре все равно "-1".

 

ListBox1.Count  тоже начинает "глючить". Не показывает верное значение, пока повторно не установишь /сбросишь значение в TSearchBox. 

 

Пробовал после использования TSearchBox вообще этот объект "убивать". Все равно последствия его применения остаются.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
  • 0

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

 

Помогает тупое передергивание значение фильтра, пусть даже он был пустой:

 

var s : string;
begin
  ListBox1.Items.Delete(0);
  //
  s := SearchBox1.Text;
  SearchBox1.Text := s+'`';
  SearchBox1.Text := s;
end;
 
Примерно таким путем можно бороться с ошибкой при добавлении итемов (убрать сортировку, добавить итем, дернуть фильтр, последняя строка наша добавленная, восстанавливаем состояние на момент "до добавления"), но как-то все это.... стыдновато за такой код. :-(

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
  • 0

Готового решения на просторах интернета не нашел. То, что напридумывал сам, оформил в виде хелпера к TListBox. Может кому пригодится.

Реализовал только необходимые мне методы. И только для режима MultiSelectStyle=None

Самое главное, что так индекс возвращается корректно.

unit ListBoxHelper;

interface

uses FMX.Controls, FMX.Types, System.SysUtils, FMX.ListBox, FMX.SearchBox;


// Создаем Helper для класса TListBox
type
  TListBoxHelper = class helper for TListBox
    function ResetFilter : string;                                // возвращает старый фильтр
    function GetSearchBox : TSearchBox;                           // возвращает SearchBox
    function AddAndClearSelect(const S : string) : integer;       // добавить, ничего не выбирать, фильтр очистить
    function AddAndSelect(const S : string) : integer;            // добавить, выбрать, фильтр очистить
    function AddAndSaveOldSelect(const S : string) : integer;     // добавить, сохранить выбор, фильтр очистить
    function AddAndSaveOldView(const S : string) : integer;       // добавить, сохранить выбор и фильтр, вернуть номер добавленного в отфильтрованном списке, или -1 если не попадает в фильтр
    procedure DeleteItem(const i : integer = -1);                 // удалить по индексу. если индекс не указан то удалить выбранный
  end;
implementation


function TListBoxHelper.GetSearchBox : TSearchBox;
var
  Child     : TControl;
  FxmChild  : TFmxObject;
begin
  Result := nil;
  for Child in self.Controls do
    for FxmChild in Child.Controls do
      if FxmChild is TSearchBox then Exit( TSearchBox( FxmChild ) );
end;

function TListBoxHelper.ResetFilter : string;
var
  s   : TListBoxItem;
  sb  : TSearchBox;
begin
  Result := EmptyStr;
  s := Selected;
  sb := GetSearchBox;
  if Assigned( sb ) then begin
    Result  := sb.Text;
    sb.Text := EmptyStr;
  end;
  if Assigned( FilterPredicate ) then FilterPredicate := nil;
  if Assigned( s ) then ItemIndex := s.Index;
end;

function TListBoxHelper.AddAndClearSelect(const S : string) : integer;
begin
  ClearSelection;
  ResetFilter;
  Result := Items.Add( s );
end;

function TListBoxHelper.AddAndSelect(const S : string) : integer;
begin
  Result := AddAndClearSelect( s );
  if Result <> -1 then ItemIndex := Result;
end;

function TListBoxHelper.AddAndSaveOldSelect(const S : string) : integer;
var
  sel   : TListBoxItem;
begin
  sel := Selected;
  Result := AddAndClearSelect( s );
  if Assigned( sel ) then ItemIndex := sel.Index
end;

function TListBoxHelper.AddAndSaveOldView(const S : string) : integer;
var
  sb          : TSearchBox;
  iSel, iNew  : TListBoxItem;
  flt         : string;
begin
  iSel := Selected; iNew := nil;
  ClearSelection;
  sb := GetSearchBox;
  flt := ResetFilter;
  //
  Result := Items.Add( s );
  if Result <> -1 then iNew := ItemByIndex( Result );
  //
  if flt <> EmptyStr then begin
    sb.Text := flt;
    if Assigned( iNew ) then Result := iNew.Index;
  end;
  if Assigned( iSel ) then ItemIndex := iSel.Index;
end;

procedure TListBoxHelper.DeleteItem(const i : integer = -1);
var
  sb          : TSearchBox;
  flt         : string;
  iSel, iDel  : TListBoxItem;
begin
  if i > Count-1 then Exit;
  sb := GetSearchBox;
  if i > -1 then begin
      iSel := Selected;
      iDel  := ItemByIndex( i );
  end
  else begin
      iSel  := nil;
      iDel := Selected;
  end;
  flt := ResetFilter;
  if Assigned( iDel ) then Items.Delete( iDel.Index );
  //
  if flt <> EmptyStr then sb.Text := flt;
  if Assigned( iSel ) then ItemIndex := iSel.Index;
end;

end.

Еще на XE7 есть глюк в режиме Sorted := True, при добавить одинаковые значения (или несколько одинаковых) и сразу выделении одного через IntemIndex.

Но пока на выявление закономерностей и борьбу нет времени.

ListBoxHelper.zip

Изменено пользователем Belov.V.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
  • 0

Не могу представить себе ситуации когда для текущей реализации листбокса понадобится поиск. Ведь листбокс жутко подлагивает если в нем много элементов, да что уж там, после 30 уже начинается. ListView наше все...

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
  • 0

Не могу представить себе ситуации когда для текущей реализации листбокса понадобится поиск. Ведь листбокс жутко подлагивает если в нем много элементов, да что уж там, после 30 уже начинается. ListView наше все...

 

Соглашусь с тем, что он действительно очень глючный. И без поиска, достаточно Sorted. Но иногда с ним проще.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
  • 0

Но иногда с ним проще.

чем проще?

Изменено пользователем wamaco

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
  • 0

 

Но иногда с ним проще.

чем проще?

 

 

Я за себя говорю. Давайте не будем углубляться в этот вопрос.

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Для публикации сообщений создайте учётную запись или авторизуйтесь

Вы должны быть пользователем, чтобы оставить комментарий

Создать учетную запись

Зарегистрируйте новую учётную запись в нашем сообществе. Это очень просто!

Регистрация нового пользователя

Войти

Уже есть аккаунт? Войти в систему.

Войти


  • Похожий контент

    • От x11
      Можно ли во время работы программы вызвать Items editor, который я вызываю во время дизайна приложения?
      Или свой лисапет создавать?
    • От x11
      Процедура добавления Item
       
      procedure TfmEditObject.AddPhoto(Image: TBitmap); Var item: TListBoxItem; imageV: TImageViewer; begin item := TListBoxItem.Create(lbPhotos); item.parent := lbPhotos; item.text := ''; item.Width := lbPhotos.Width; item.PopupMenu := PopupMenu1; imageV := TImageViewer.Create(lbPhotos); imageV.HitTest := False; imageV.Parent := item; imageV.Align := TAlignLayout.Client; imageV.Bitmap.Assign(image); item.SetFocus; end; У popupmenu есть 2 пункта, привязанных к Action.
       
      Gestures срабатывает на "long tap"
      procedure TfmEditObject.lbPhotosGesture(Sender: TObject; const EventInfo: TGestureEventInfo; var Handled: Boolean); var c: IControl; ListBox: TListBox; lbxPoint: TPointF; ListBoxItem: TListBoxItem; begin if EventInfo.GestureID = igiLongTap then if (sender is TListBox) and assigned(TListBox(sender).Selected) then begin c := ObjectAtPoint(EventInfo.Location); if Assigned(c) then if Assigned(c.GetObject) then if c.GetObject is TListBox then begin ListBox := TListBox(c.GetObject); lbxPoint := ListBox.AbsoluteToLocal(EventInfo.Location); ListBoxItem := ListBox.ItemByPoint(lbxPoint.X, lbxPoint.Y); if Assigned(ListBoxItem) then PopupMenu1.Popup(lbxPoint.X, lbxPoint.Y); Handled := True; end; end; end;  
      Ставил точку останова, видно, что до строки "PopupMenu1.Popup(lbxPoint.X, lbxPoint.Y);" доходит.
      Если программа работает на Windows, то меню отображается по правой кнопке мышки, а на андроид устройстве меню не отображается по Long Tap.
       
      Как видно из кода, то меню прикручивается к ListBoxItem, а непосредственно к TListBox меню прикрутил в дизайне.
    • От x11
      Хочу реализовать прокрутку фото с помощью TListBox.
      Пока что в дизайне добавил пару Item и кинул на них TImageViewer, ну и картинку туда вставил.
      В свойстве TListStyle указал Horizontal. На Windows не листается мышкой влево/вправо, но есть хотя бы полоса прокрутки внизу.
      На андроид-устройстве и не листается, и полосы прокрутки нет вообще.
      Это связано с этим вопросом http://fire-monkey.ru/topic/4301-выводотображение-нескольких-картинок-на-форме
    • От x11
      В свойстве TListBox.ListStyle установил значение Horizontal. Список поменял вид.
      Теперь ставлю Vertical, но ничего не происходит.
      Как вернуть стиль списка обратно к вертикальному?
    • От Morfi
      Ребята, как правильно настроить или реализовать поиск в TCombobox (данные которого связаны через livebinding c БД) при помощи TSearchBox?
    • От Euvene
      Добрый день, возникла такая проблемка: при добавлении в ListBoxItem компонента TEdit если поставить ему TControlType::Platform он вылазит за пределы ListBox но при Styled все норм, кто нибудь сталкивался и как с этим бороться?


    • От ENERGY
      Что лучше в плане производительности использовать из этих компонентов для Android и iOS?
      Мне показалось что TlistBox как то дольше создается и грузится (я использую фрэймы (TFrame), которые создаются в RunTime, но сделаны они в Design Time) 
      На компоненте будут лежать Editbox 2x, лэйблы, Tmemo, DateEdit, TimeEdit.
      TListBox удобен тем что (я так понимаю) он автоматом подстроит визуальный стиль заголовков и пунктов под текущую систему (fix me?).
      А вот TScrollBar это не сделает. Кстати, если использовать этот компонент, скроллбар, как отделить пункты рамкой (горизонтальной чертой?). Может есть какой то межплатформенный TBorder, который отображается в нужной стиле? А если использовать TLine то какого цвета его делать (DarkGray?), кто нибудь знает?
      Спасибо.
    • От chaplin.u@gmail.com
      Как сделать разделители между итемами. Как на картинке.

    • От AlexG
      Привет друзья!
      Возникла странная ситуация при работе с TListBox. А именно - при попытке прокрутки списка в его конец.
      Условно:
      - есть список итемов (сообщения чата);
      - загрузка сообщений происходит в процедуре "синхронизированной" с главным потоком и заключена в TListBox(listbox1).BeginUpdate  и TListBox(listbox1).EndUpdate;
      - все замечательно грузится
      НО! После загрузки Итемов требуется прокрутить список в его конец. И вот тут начинаются "приколы".
      Как только не пытаться прокрутить список в его конец (разные способы, см.ниже) - всегда получается, что список прокручивается до конца, но немного "откатывается" вверх. Размер его автоматического скролла "обратно" зависит от количества Item в TListBox! Чем больше кол-во Item - тем больше назад откатывается скролл.
      Способы прокрутки в конец списка - значения не имеют. Всегда одно и то же.
      procedure TChatListBoxEx.ScrollToLast; var   Item: TListBoxItem; begin // ВАРИАНТ 1   Item := ListItems[Items.Count - 1];   if Assigned(Item) then     ScrollToItem(Item); // ВАРИАНТ 2   ViewportPosition:= TPointF.Create(0, Item.ParentedRect.Top); // ВАРИАНТ 3   ScrollBy(0, ViewportPosition.Y - Item.ParentedRect.Top); // ВАРИАНТ 4   BeginUpdate;   try     ItemIndex := Items.Count - 1;   finally     EndUpdate;   end; end; Предупреждая ваши вопросы, сразу скажу - пробовал и другие варианты, просто перечислять не стал все. Пробовал и эмитировать нажатие клавиши END при "активном" списке.
      Все синхронизируется, типа 
      TThread.Synchronize(nil, listbox1.ScrollToLast); Эффект всегда один и тот же...
      НО! Если загрузить список, независимо от кол-ва элементов списка, а потом в программе вызвать ScrollToLast, подождав некоторое время, а не сразу, например по нажатию на какую-нибудь кнопку, то список прокрутится в конец НОРМАЛЬНО!
      Будьте добры - кто сталкивался с подобной ситуацией, или кто что-то может посоветовать?
      Или наши Гуру смогут ответить на этот вопрос?
      Видео, чтобы было понятнее что происходит, прилагаю.
      RAD Studio 10.1 Berlin (эффект наблюдается на всех версиях Windows - XP, Vista, 7, 8, 10. На других ОС пока не пробовал...)
      Заранее благодарен!
      P.S. Возник вопрос (как вариант решения проблемы) - как узнать, что произошло событие окончания отрисовки TListBox? А именно - список заполнился, выполнилась отрисовка и можно прокручивать.
    • От M1shQa
      Есть один листбокс..) В общем парился я парился, так и не понял как запилить стиль по человечески для итемов в боксе и нашел кнопку Edit default Style. Нашел куда впилить TimageViewer и поставил ему свойство client. Все бы ничего, да вот размер итемов не статичен, а картинка не растягивается, к тому же pngшная картинка не отделяется от фона. Подскажите, как картинку растягивать в зависимости от длины и ширины итемов листбокса и как правильно юзать pngшные картинки (что бы они сохраняли прозрачность). Может я вообще не туда рою и нужно другими способами вставлять картинки под каждый item? Видел много гайдов под listview, но к сожалению мне нужно именно для бокса..
      ----
      п.с. что бы было проще: как нарисовать ровную плашку позади каждого элемента листбокс?
  • Последние посетители   0 пользователей онлайн

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