Wszystkie elementy TListboxItem w zmiennej

0

Witam. Dodawanie pozycji do ListBox w pętli która za każdym razem robi items.add() na komputerze działa na tyle szybko, że nie trzeba się tym przejmować. Na telefonie z androidem niestety działa to już znacznie gorzej i do czasu kiedy się wykonuje aplikacja "stoi" (galaxy s3 nowy nie jest ale do ślimaków jeszcze chyba nie należy).

Rozwiązaniem tego jest dodawanie w pętli wszystkich pozycji do zmiennej TStrings i późniejsze wykonanie ListBox.items := zmienna; Niestety nie mam pojęcia do jakiej zmiennej dodać elementy listy typu TListboxItem, TSearchBox, TListBoxGroupHeader itd. Chodzi o to aby w kodzie do zmiennej dodawać takie elementy a później jakimś assign czy jakoś tak przypisać całość do zawartości tego ListBox.

Znajdzie się ktoś obeznany i chętny do pomocy? z góry dziękuję

0

Jeżeli masowo dodajesz nowe pozycje np. do komponentu klasy TListBox - powinieneś wywołać metodę BeginUpdate przed pętlą i EndUpdate za pętlą; Dzięki temu komponent nie będzie aktualizował interfejsu po każdej dodanej pozycji, co powinno mocno przyspieszyć całą operację; To samo rób przy selektywnym usuwaniu pozycji z komponentu lub przy ich edycji;

Zobacz tu: http://www.festra.com/eng/tip-beginupdate.htm


Ewentualnie jeśli potrzebujesz zaminić zawartość komponentu na inną (czyli usunąć starą zawartość i ustawić nową - inną) to możesz utworzyć obiekt klasy TStringList, uzupełnić go w pamięci i zaaplikować do komponentu za pomocą ListBox.Items.Assign; Przykład:

procedure TForm1.Button1Click(Sender: TObject);
var
  slNewContent: TStringList;
  intLineIdx: Integer;
begin
  slNewContent := TStringList.Create();
  try
    for intLineIdx := 0 to 9999 do
      slNewContent.Add('foo bald bar');
  finally
    ListBox1.Items.Assign(slNewContent);
    slNewContent.Free();
  end;
end;

Komponent także powinien zostać tylko raz przemalowany, więc też będzie to szybka metoda zmiany zawartości.

0

Dokładnie o ten drugi sposób mi chodzi gdyż dodawania na telefonie nawet z użyciem BeginUpdate trwa przytłaczająco długo. Problem tkwi w tym, że lista stringów nie może być użyta. Chodzi o taką listę która potrafi pomieścić w każdej pozycji elementy typu TListboxItem, TListBoxHeader, TListBoxGroupHeader itd. i dopiero taką tablicę obiektów przypisać jednym machnięciem do listy.

0

Nie sądzę, aby klasa takiej listy była dostępna w bibliotece standardowej; A nawet jeśli taką byśmy napisali, to w jaki sposób chcesz uzupełnić komponent w dane z takiej listy?

O ile mi wiadomo, komponenty zarządzają swoimi podobiektami wewnętrznie, nie udostępniając ich na zewnątrz; Jedynym środkiem dostępu do nich (pośrednim) są właściwości i metody, które odpowiednio operują na tych prywatnych podobiektach;

Chyba że masz fizycznie dostęp do listy itemów np. klasy TListBoxItem?

0

myślałem, że będzie to coś w stylu:

var
	zListBoxItem: TListboxItem;
  zListBoxGroupHeader: TListBoxGroupHeader;
  zLista: TajemniczaKlasa;
  i: integer;
begin   
  ListBox.Items.Clear;
  
	for i:=0 to 1000 do begin
  	zListBoxItem := TlistBoxItem.Create(ListBox);
    
    zListBoxItem.StyleLookup := 'listboxitembottomdetail';
    zListBoxItem.Text := 'Text ' + inttostr(i);
    zListBoxItem.ItemData.Detail := 'Detal ' + inttostr(i);
    zLista.Add( zListBoxItem );
    application.ProcessMessages;
  end;

  ListBox.items.Assign( zLista );
end;

Co konkretnie masz na myśli "fizyczny dostęp"? Jeżeli chodzi o pliki typu FMX.Types.pas czy FMX.ListBox.pas to mam do nich dostęp i pogrzebać tam się da tylko nie ruszam jak się nie znam ;)

0

Co konkretnie masz na myśli "fizyczny dostęp"?

Teraz to już nic - widzę, że Twój komponent ListBox ma inną budowę niż ten, który ja znam; W każdym razie masz dostęp poprzez metody, np. Add;

No ale działa Ci ten kod który podałeś, czy nie działa?
Jeżeli działa i dodaje pozycje, ale zbyt wolno, to spróbuj użyć metod BeginUpdate i EndUpdate.

0

Ten który teraz podałem jest czysto hipotetyczny. Chodzi o to, że dodaje do listy itemki a na końcu taką listę przypisuje do ListBox. Problem w tym jakiego typu powinna być taka lista. Problem tym większy, że jako dużo bardziej doświadczony programista nie kojarzysz takiej klasy co może skazać mnie na powolne pętle i BeginUpdate

0

Po prostu @furious programming nigdy nie napisał nic pod Androida pod XE ani może i Fire Monkey. Problem jest mi znany. I rozwiązania z VCL czy WinAPI nijak się mają do FMX. Ale odnosze wrażenie że mam dejavu. Już podobny wątek był i kombinowaliśmy różne rozwiązania. Okazało się, że można maksymalnie dodać do około 100 itemów w rozsądnym czasie.

Wnioskiem z tamtego wątku było, że albo dodajemy wszystko do TList/tablicy i wyświetlamy po kawałku przy scrollowaniu. A czy TListView też niedomaga pod Androidm? Bo nie pamiętam. A teraz nie mam jak sprawdzić.

Edit: znalażłem tersz tamten wątek. Jest tutaj Powolne działanie aplikacji skompilowanych na android i teraz pozostaje pytanie jak zassignowač wszystko. Zdaje się mi że gdy dla TListBox robimy assign z TStringList to obiekty również się przypiszą.

0

Problem tym większy, że jako dużo bardziej doświadczony programista nie kojarzysz takiej klasy co może skazać mnie na powolne pętle i BeginUpdate

Nie kojarzę, bo nie programuję pod Androida ani nie korzystam ze środowisk Delphi; Normalna znana mi z Lazarusa i starych wersji Delphi klasa TListBox posiada jedynie właściwość Items klasy TStringList; Na desktopach wystarczy użyć metod BeginUpdate i EndUpdate, aby maksymalnie przyspieszyć uzupełnianie czy modyfikacje zawartości komponentu;

Pamiętam też wątek, w którym ktoś narzekał na potwornie wolne operacje dodawania itemów do ListBox i nijak nie dało się tego rozwiązać za pomocą znanych zabiegów (m.in. wymienionych metod *Update); Jeśli one nie pomagają i w Twoim przypadku, to trzeba szukać w Google jakichś tipów czy wątków na StackOverflow - być może ktoś rozwiązał ten problem nieco inaczej, być może dużo kombinował.

2

Z helpa

Note: FMX.ListBox.TListBox performance can be slow on mobile. Use TListView if you want to develop more complex applications, especially apps with large databases.
http://docwiki.embarcadero.com/RADStudio/XE8/en/Mobile_Tutorial:_Using_ListBox_Components_to_Display_a_Table_View_%28iOS_and_Android%29
Wprawdzie piszą o bazach danych ale to na pewno chodzi o to że w ogóle TListBox jet wolny na platformach mobilnych i lepiej użyć TListView.

0

Bardzo dziękuję za zainteresowanie tematem. Jak się okazało faktycznie ListBox jest wolniejszy od ListView. Dotyczy to jednak projektów "Multi-Device Application" ponieważ w zwykłym VCL i pętli listbox1.items.add(''); trwa to ułamki sekundy nawet przy 5000 elementów. Gdy tylko kAzek uświadomił mi co jest napisane w tym tutku to praca nabrała sensu a efekty są bardzo dobre. Tak to bym pewnie siedział tydzień nad ListBox i nic nie wyczarował ;)

@furious programming - Różnica w budownie wynika właśnie z tego, że to jest projekt FMX i tam kontrolki mają inne właściwości.

procedure TMainForm.Button2Click(Sender: TObject);
var
  item: TListboxItem;
  i: integer;
begin   
   listbox2.Items.Clear;

  for i:=0 to strtoint(edit1.Text) do begin
    item := TListBoxItem.Create(listbox2);
    item.Text := 'item';
    item.StyleLookup := 'listboxitembottomdetail';
    item.ItemData.Detail := 'detal ' + inttostr(i);
    item.ItemData.Accessory := TListBoxItemData.TAccessory(1);
    listbox2.AddObject( item );
    
    Label_Main.Text := inttostr(i);
    application.ProcessMessages;
  end;
end;

procedure TMainForm.Button4Click(Sender: TObject);
var
  Item: TListViewItem;
  i: integer;
begin
  listview1.Items.Clear;

  for i:=0 to strtoint(edit2.Text) do begin 
    item := listview1.Items.Add;
    Item.Text := 'item';
    Item.Data[TMultiDetailAppearanceNames.Detail1] := 'detal ' + inttostr(i);
    Item.Objects.AccessoryObject.AccessoryType := TAccessoryType(2);

    Label_Main.Text := inttostr(i);
    application.ProcessMessages;
  end;
end;

A oto porównanie przybliżonych czasów ładowania:

ListBox 100 elementów: 15s(Tel) - <2s(PC)
ListBox 500 elementów: 4m20s(Tel) - 15s(PC)
ListBox 1000 elementów: 30s(PC)

ListView 100 elementów: 2s(Tel) <1s(PC)
ListView 500 elementów: 8s(Tel) <1s(PC)
ListView 1000 elementów: 18s(Tel) <2s(PC)
ListView 5000 elementów: 7s(PC)

4

@PinoWiktor - nadal nie używasz BeginUpdate i EndUpdate, a trąbię o tym już od kilku postów :]

Metody te blokują odświeżanie komponentu po zmianie jego zawartości, więc i w TListView z nich korzystaj; Poza tym nie wiem po co w pętli masz Appplication.ProcessMessages - przecież to tylko opóźnia uzupełnienie komponentu;
____W dokumentacji masz taki przykład:

var
  LItem: TListViewItem;
  I: Integer;
begin
  for I := 1 to 10 do
  begin
    LItem := ListView1.Items.Add;
    LItem.Text := IntToStr(I); 
  end;
end;
 
// To achieve the best performance use BeginUpdate and EndUpdate.
 
var
  LItem: TListViewItem;
  I: Integer;
begin
  ListView1.BeginUpdate;
  try
    for I := 1 to 10 do
    begin
      LItem := ListView1.Items.Add;
      LItem.Text := IntToStr(I);
    end;
  finally
    ListView1.EndUpdate;
  end;
end;

w którym komentarz mówi co trzeba zrobić, aby maksymalnie przyspieszyć operacje na komponencie:

// To achieve the best performance use BeginUpdate and EndUpdate.

Więc swoje kody powinieneś wyposażyć w te metody i dopiero wtedy testować szynkość kodów.

0

Teraz to jest petarda. Wywaliłem Appplication.ProcessMessages przy czym jednak nie widzę różnicy z użyciem BeginUpdate i bez (nawet przy 10000 itemów). Być może aplikacje FMX inaczej jakoś renderują elementy i stąd to wynika. Też taka ciekawostka, że po uruchomieniu aplikacji tego typu na komputerze fraps wyświetla na formatce swój licznik ;)

Wracając do tematu to serdeczne dzięki za pomoc. Śmiga to aż miło patrzeć. Gdy zaczynałem z tym zabawę nie przypuszczałem nawet, że może to tak sprawnie działać.

1

z moich krótkich doświadczeń z fxm i androidem

  1. jeśli testujesz coś na emulatorze i jest wolno to nie jest to żadnym wyznacznikiem - program działa znacznie szybciej na dwuletniej xperii M niż na emulatorze działającym na i5 z 16GB ram. Nawet nie wspominam o jakimś lepszym tablecie.
  2. dla testów mam na formie listboxa, parę labeli. Dane ładuję do dataseta z sqlitea i wszystko wiążę wizualnie. Dodane grupowanie i wyszukiwanie. Jak dla mnie szybkość działania jest poprawna.
    Czyli zamiast ładować wszystko przez Add ładuj najpierw do jakiegoś dataseta (np. do pamięci) i podpinaj już jego jako źródło danych
0

testy oczywiście na telefonie bo faktycznie te emulatory chyba są zrobione dla zasady. Posiadam też BlueStacks który emuluje androida bardzo ładne lecz aplikacji pisanych w delphi nie obsługuje (może da się jakoś ustawić środowisko ale domyślnie jest klops). Jeżeli chodzi o wiązania wizualne to dla mnie czarna magia trochę i cała obsługa baz z tym związana (przesiadka z D6 na XE7 była lekkim szokiem). To o czym piszesz jest w zasadzie tym o czym myślałem rozpoczynając temat jednak otrzymana pomoc rozwiązała mój problem bo moja wiedza na temat baz danych jest taka, że idHttp łączy się przygotowaną stroną PHP wyświetlającą dane z mysql w formie tekstowej i później sobie to program analizuje i w pętlach dodaje gdzie trzeba (wiem, że to rzeźbienie w g*** ale dla mojej aplikacji wystarczy mam nadzieję).

Jeżeli masz jakieś łopatologiczne metody przypisania tak pobranych danych do bazy (pobrać, zapisać, przypisać do listy) to chętnie się zapoznam gdyż lepiej pobrać dane z telefonu niż za każdym razem odpytywać serwer o te same dane.

1

wiesz co ja poczytałem przykłady na stronie embarcadero i bardziej metodą prób i błędów (klikać ile wlezie aż zadziała :p)

0
PinoWiktor napisał(a):

Posiadam też BlueStacks który emuluje androida bardzo ładne lecz aplikacji pisanych w delphi nie obsługuje (może da się jakoś ustawić środowisko ale domyślnie jest klops).
Oczywiście że obsługuje ale jakoś nie chce instalować aplikacji przez BlueStack App Handler (czyli domyślnie uruchamiany np. przez kliknięcie na ikonę .apk) tylko trzeba wrzucić apkę np. przez przeciągnięcie na emulator lub zwyczajne skopiowanie do folderu współdzielonego c:\ProgramData\BlueStacks\UserData\SharedFolder\ a później uruchamiać przez np.: ES File Explorer (wchodzisz do Windows -> BstSharedFolder). Jak nie masz ES File Explorer to go pobierz http://www.estrongs.com/?lang=en on się powinien bez problemu zainstalować.

0

Bez względu na metodę instalacji po uruchomieniu wyświetla się błąd "Application does not support this device". Poszperałem trochę i znalazłem.

Project -> Deployment po czym odznaczyłem pozycję o nazwie libnative-activity.so ze ścieżką *library\lib\x86*. W opisach było o usunięciu *library\lib\armeabi* ale to nie dało efektu.

Co do nauki sqlite pozostaje mi metoda abrakadaber :)

1 użytkowników online, w tym zalogowanych: 0, gości: 1