CYFROWY BARON • PROGRAMOWANIE • Zobacz wątek - ListView1->OwnerData = true; zmiana danych

ListView1->OwnerData = true; zmiana danych

dział ogólny

ListView1->OwnerData = true; zmiana danych

Nowy postprzez Darek_C++ » niedziela, 15 maja 2011, 19:32

Witam ponownie,
Jeśli właściwość ListView1->OwnerData = true; wczytywanie nawet 200.000 lini danych wykonuje się bardzo szybko co realizuje następującym kodem:

KOD cpp:     UKRYJ  
//---------------------------------------------------------------------------
void __fastcall TForm1::FormCreate(TObject *Sender)
{
        ListView1->OwnerData = true;
        ListView1->OnData = ListView1Data;
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button2Click(TObject *Sender)
{
        int elementow ;
        OpenTextFileDialog1->Filter = "Pliki TXT *.txt|*.txt|";
        OpenTextFileDialog1->DefaultExt = "txt";
        if(OpenTextFileDialog1->Execute())
        {
                ListView1->Clear();
                Memo1->Clear();
                String plik = OpenTextFileDialog1->FileName;
                ListaVirt = new TStringList();
                ListaVirt->LoadFromFile(plik);
                elementow = ListaVirt->Count;
                ListView1->Items->Count = elementow;
                StatusBar1->Panels->Items[0]->Text="Lista zawiera "+IntToStr(elementow)+" adresów";
        }

}
//---------------------------------------------------------------------------
void __fastcall TForm1::ListView1Data(TObject *Sender, TListItem *Item)
{
        Item->Caption = (String) Item->Index;
        Item->SubItems->Add(ListaVirt->Strings[Item->Index].Trim());
        Item->SubItems->Add("---");
        Item->SubItems->Add("---");
        Item->SubItems->Add("---");
 }
//---------------------------------------------------------------------------
void __fastcall TForm1::ListView1Click(TObject *Sender)
{
        if(ListView1->Selected )
        {
                int nrNaListViev = ListView1->Selected->Index;
                Memo1->Lines->Add(ListView1->Items->Item[nrNaListViev]->SubItems->Strings[0]);
                ListView1->Items->Item[nrNaListViev]->SubItems->Strings[1] = "OK";
        }
}


Ale w jaki sposób zmienić przykładowo dane w trzeciej kolumnie które po wczytania zawierają " --- " na np "sprawdzony".

Takie coś nie działa :(

KOD cpp:     UKRYJ  
void __fastcall TForm1::Button4Click(TObject *Sender)
{
        ListView1->Items->Item[0]->SubItems->Strings[1] = "Sprawdzony";
}

Proszę o pomoc.....
Avatar użytkownika
Darek_C++
Elektrowied
Elektrowied
 
Posty: 454
Dołączył(a): piątek, 25 lipca 2008, 14:33
Podziękował : 66
Otrzymał podziękowań: 4
System operacyjny: Windows XP Pro SP2
Kompilator: Turbo Explorer C++
Gadu Gadu: 0
    Windows XPFirefox

Re: ListView1->OwnerData = true; zmiana danych

Nowy postprzez Cyfrowy Baron » niedziela, 15 maja 2011, 21:01

Musisz utworzyć w pamięci jakąś listę i w zdarzeniu onData przepisywać do ListView zawartość tej listy. Potem niczego już nie modyfikujesz w ListView, lecz modyfikujesz zawartość tej listy w pamięci. ListView będzie automatycznie pobierał zawartość tej listy i aktualizował własną zawartość.

Prosty przykład:

Plik nagłówkowy np. Unit1.h
KOD cpp:     UKRYJ  
private:
         TStringList *SubItem1;
         TStringList *SubItem2;


Plik źródłowy np. Unit1.cpp
KOD cpp:     UKRYJ  
TForm1 *Form1;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
        : TForm(Owner)
{
 ListView1->Items->Count = 10;

 SubItem1 = new TStringList;
 SubItem2 = new TStringList;

 for(int i = 0; i < 10; i++)
 {
   SubItem1->Add("SubItems_1 - wiersz: " + (String)i);
   SubItem2->Add("SubItems_2 - wiersz: " + (String)i);
 }


}
//---------------------------------------------------------------------------
void __fastcall TForm1::ListView1Data(TObject *Sender, TListItem *Item)
{
 Item->SubItems->Add( SubItem1->Strings[ Item->Index ] );
 Item->SubItems->Add( SubItem2->Strings[ Item->Index ] );
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
 /* zmiana zawartości trzeciej kolumny w ListView Licząc kolumnę Caption
        w wierszu 6, gdyż wiersze liczone są od 0 */


 SubItem2->Strings[5] = "Sprawdzony";

 /* wymuszenie odświerzenia ListView */
 ListView1->Invalidate();
}
//---------------------------------------------------------------------------


W trybie wirtualnym ListView musi być zarządzane przez dodatkowe listy. Jeżeli wprowadzasz dane jawnie w zdarzeniu OnData, to nie będziesz mógł w żaden sposób zmienić tych danych. W pliku pomocy zostało to jasno zaznaczone:


To improve the performance of a virtual list view control, cache items for quick retrieval. The OnDataHint event can help optimize retrieval from the cache.



Za ten post autor Cyfrowy Baron otrzymał podziękowanie od:
Darek_C++
Avatar użytkownika
Cyfrowy Baron
Administrator
Administrator
 
Posty: 4727
Dołączył(a): niedziela, 13 lipca 2008, 15:17
Podziękował : 12
Otrzymał podziękowań: 444
System operacyjny: Windows 7 x64 SP1
Kompilator: Embarcadero RAD Studio XE2
C++ Builder XE2 Update 4
SKYPE: cyfbar
Gadu Gadu: 0
    Windows XPFirefox

Re: ListView1->OwnerData = true; zmiana danych

Nowy postprzez Darek_C++ » poniedziałek, 16 maja 2011, 11:13

Pojawił się problem i nie wiem dlaczego tak jest:
KOD cpp:     UKRYJ  
#include <vcl.h>
#pragma hdrstop

#include "Unit1.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
        : TForm(Owner)
{
        ListView1->OwnerData = true;
        ListView1->OnData = ListView1Data;

        SubItem1 = new TStringList;
        SubItem2 = new TStringList;
        SubItem3 = new TStringList;
        SubItem4 = new TStringList;
}
//---------------------------------------------------------------------------
void __fastcall TForm1::ListView1Data(TObject *Sender, TListItem *Item)
{

        Item->Caption = (String) Item->Index;
        Item->SubItems->Add( SubItem1->Strings[ Item->Index ] );
        Item->SubItems->Add( SubItem2->Strings[ Item->Index ] );
        Item->SubItems->Add( SubItem3->Strings[ Item->Index ] );
        Item->SubItems->Add( SubItem4->Strings[ Item->Index ] );

}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
        OpenTextFileDialog1->Filter = "Pliki TXT *.txt|*.txt|";
        OpenTextFileDialog1->DefaultExt = "txt";
        if(OpenTextFileDialog1->Execute())
        {
                 SubItem1->Clear();
                 SubItem2->Clear();
                 SubItem3->Clear();
                 SubItem4->Clear();
                 ListView1->Clear();
               
                int dodanych = 0;
                String plik = OpenTextFileDialog1->FileName;
                TStringList * Lista = new TStringList();
                Lista->LoadFromFile(plik);

                for(int ii = 0; ii < Lista->Count; ii++)
                {
                        String adres = Lista->Strings[ii].Trim();
                        if(adres.IsEmpty()== false)
                        {
                           SubItem1->Add(adres);
                           SubItem2->Add("---");
                           SubItem3->Add("---");
                           SubItem4->Add("---");
                           dodanych++;
                        }
                }
                ListView1->Items->Count = dodanych;

                StatusBar1->Panels->Items[0]->Text="Lista zawiera "+IntToStr(dodanych)+" adresów";
                StatusBar1->Panels->Items[1]->Text="---";
                delete Lista; Lista = NULL;
        }
}
//---------------------------------------------------------------------------
void __fastcall TForm1::FormClose(TObject *Sender, TCloseAction &Action)
{
        delete SubItem1; delete SubItem2;
        delete SubItem3; delete SubItem4;
}

Pierwsze wgranie adresów do TListViev działa, ale przy probie ponownego wgrania wywala wyjątek typu:

Exception class EStringListError with message 'List index out of bounds (289)'. Process ProjektTest.exe (1380)


Kody wydaje się mi poprawny, a jednak gdzieś jest błąd.
---------------
Znalazłem błąd.
Powodem tego błędu było wywoływanie metody ListView1->Clear(); Po jej wykomentowaniu kod działa zgodnie z oczekiwaniem :)
Avatar użytkownika
Darek_C++
Elektrowied
Elektrowied
 
Posty: 454
Dołączył(a): piątek, 25 lipca 2008, 14:33
Podziękował : 66
Otrzymał podziękowań: 4
System operacyjny: Windows XP Pro SP2
Kompilator: Turbo Explorer C++
Gadu Gadu: 0
    Windows XPFirefox

Re: ListView1->OwnerData = true; zmiana danych

Nowy postprzez Cyfrowy Baron » poniedziałek, 16 maja 2011, 11:46

Darek_C++ napisał(a):Powodem tego błędu było wywoływanie metody ListView1->Clear(); Po jej wykomentowaniu kod działa zgodnie z oczekiwaniem :)


Powinno być:

KOD cpp:     UKRYJ  
 ListView1->Items->Clear();


Wszak masz coś takiego:

KOD cpp:     UKRYJ  
ListView1->Items->Count = dodanych;


Kasujesz listę, a nie ListView.
Avatar użytkownika
Cyfrowy Baron
Administrator
Administrator
 
Posty: 4727
Dołączył(a): niedziela, 13 lipca 2008, 15:17
Podziękował : 12
Otrzymał podziękowań: 444
System operacyjny: Windows 7 x64 SP1
Kompilator: Embarcadero RAD Studio XE2
C++ Builder XE2 Update 4
SKYPE: cyfbar
Gadu Gadu: 0
    Windows XPFirefox

Re: ListView1->OwnerData = true; zmiana danych

Nowy postprzez Darek_C++ » poniedziałek, 16 maja 2011, 11:56

U mnie nie ma takiej metody:

[C++ Error] Unit1.cpp(52): E2316 'Cleas' is not a member of 'TListItems'

Avatar użytkownika
Darek_C++
Elektrowied
Elektrowied
 
Posty: 454
Dołączył(a): piątek, 25 lipca 2008, 14:33
Podziękował : 66
Otrzymał podziękowań: 4
System operacyjny: Windows XP Pro SP2
Kompilator: Turbo Explorer C++
Gadu Gadu: 0
    Windows XPFirefox

Re: ListView1->OwnerData = true; zmiana danych

Nowy postprzez Cyfrowy Baron » poniedziałek, 16 maja 2011, 12:00

Literówka! :? Wkradł się błąd, który już poprawiłem. Powinno być oczywiście Clear().
Avatar użytkownika
Cyfrowy Baron
Administrator
Administrator
 
Posty: 4727
Dołączył(a): niedziela, 13 lipca 2008, 15:17
Podziękował : 12
Otrzymał podziękowań: 444
System operacyjny: Windows 7 x64 SP1
Kompilator: Embarcadero RAD Studio XE2
C++ Builder XE2 Update 4
SKYPE: cyfbar
Gadu Gadu: 0
    Windows XPFirefox

Re: ListView1->OwnerData = true; zmiana danych

Nowy postprzez Darek_C++ » poniedziałek, 16 maja 2011, 12:11

Ale po dodaniu tej metody ListView1->Items->Clear(); też pojawia się wyjątek podczas ponownego wczytywania danych:

First chance exception at $7C812AFB. Exception class EStringListError with message 'List index out of bounds (289)'. Process Program1Test.exe (3644)

Avatar użytkownika
Darek_C++
Elektrowied
Elektrowied
 
Posty: 454
Dołączył(a): piątek, 25 lipca 2008, 14:33
Podziękował : 66
Otrzymał podziękowań: 4
System operacyjny: Windows XP Pro SP2
Kompilator: Turbo Explorer C++
Gadu Gadu: 0
    Windows XPFirefox

Re: ListView1->OwnerData = true; zmiana danych

Nowy postprzez Cyfrowy Baron » poniedziałek, 16 maja 2011, 12:20

TO chyba dlatego, że w trybie wirtualnym ListView musi zawierać ileś tak wierszy, więc zamiast czyścić listę ustaw jej wartość na 0 lub 1.

Za ten post autor Cyfrowy Baron otrzymał podziękowanie od:
Darek_C++
Avatar użytkownika
Cyfrowy Baron
Administrator
Administrator
 
Posty: 4727
Dołączył(a): niedziela, 13 lipca 2008, 15:17
Podziękował : 12
Otrzymał podziękowań: 444
System operacyjny: Windows 7 x64 SP1
Kompilator: Embarcadero RAD Studio XE2
C++ Builder XE2 Update 4
SKYPE: cyfbar
Gadu Gadu: 0
    Windows XPFirefox

Re: ListView1->OwnerData = true; zmiana danych

Nowy postprzez Darek_C++ » poniedziałek, 16 maja 2011, 12:30

Jeśli ustawię ListView1->Items->Count = 0; program się nie wysypuje :)
Avatar użytkownika
Darek_C++
Elektrowied
Elektrowied
 
Posty: 454
Dołączył(a): piątek, 25 lipca 2008, 14:33
Podziękował : 66
Otrzymał podziękowań: 4
System operacyjny: Windows XP Pro SP2
Kompilator: Turbo Explorer C++
Gadu Gadu: 0
    Windows XPFirefox

Re: ListView1->OwnerData = true; zmiana danych

Nowy postprzez Cyfrowy Baron » wtorek, 17 maja 2011, 08:43

Sprawdziłem to i już wiem, że nie można czyścić tej listy w trybie wirtualnym. Wystarczy po prostu podać nową ilość wierszy. ListView przecież nie zawiera na własnej liście żadnych danych, lecz pobiera dane z list zewnętrznych.

Pamiętaj, że po każdej zmianie zawartości list zewnętrznych trzeba wymusić odrysowanie ListView:

KOD cpp:     UKRYJ  
ListView1->Invalidate();


Jeżeli tego nie zrobisz, to okno odświeży się dopiero gdy zajdzie konieczność przerysowania całego okna programu np. po zmianie rozmiaru okna, po minimalizacji, maksymalizacji, itp.
Avatar użytkownika
Cyfrowy Baron
Administrator
Administrator
 
Posty: 4727
Dołączył(a): niedziela, 13 lipca 2008, 15:17
Podziękował : 12
Otrzymał podziękowań: 444
System operacyjny: Windows 7 x64 SP1
Kompilator: Embarcadero RAD Studio XE2
C++ Builder XE2 Update 4
SKYPE: cyfbar
Gadu Gadu: 0
    Windows XPFirefox


  • Podobne tematy
    Odpowiedzi
    Wyświetlone
    Ostatni post

Powrót do Ogólne problemy z programowaniem

Kto przegląda forum

Użytkownicy przeglądający ten dział: Brak zalogowanych użytkowników i 6 gości

cron