CYFROWY BARON • PROGRAMOWANIE • Zobacz wątek - Wczytanie z pliku do StringGrid

Wczytanie z pliku do StringGrid

dział ogólny

Wczytanie z pliku do StringGrid

Nowy postprzez duf » poniedziałek, 20 września 2010, 08:59

Nie mogę wczytać pliku bezpośrednio do StringGrida. Po pierwszej linii plik zostaje zamknięty:
Kod: Zaznacz cały
while( getline( wfstr, dane, L'\n' ) )
{
   StringGrid1->RowCount = ++row;
}

Jest to dziwne bo muszę zrobić to pośrednio poprzez np vector co kompletnie jest dla mnie bez sensu. Czy da się to wytłumaczyć?
Avatar użytkownika
duf
Intelektryk
Intelektryk
 
Posty: 175
Dołączył(a): czwartek, 9 października 2008, 13:02
Podziękował : 17
Otrzymał podziękowań: 2
System operacyjny: Windows 10
Kompilator: XE8
Gadu Gadu: 0
    Windows XPFirefox

Re: Wczytanie z pliku do StringGrid

Nowy postprzez Cyfrowy Baron » poniedziałek, 20 września 2010, 09:36

Przede wszystkim to nie pokazałeś tutaj kodu odpowiedzialnego za wczytywanie pliku do obiektu typu TStringGrid, a jedynie kod odpowiedzialny za zwiększanie wartości wierszy w tabeli. Zmienna RowCount odpowiada jedynie za całkowitą liczbę wierszy. Obiekt StringGrid nie posiada żadnej wbudowanej funkcji, która umożliwiałaby wczytanie pliku do tej tabeli. Tabelę należy wypełniać poprzez właściwość Cells[x][y] tego obiektu.
Przykład zapisywanie i odczytywania tabeli znajdziesz w serwisie Cyfrowy Baron w dziale: porady -> StringGrid -> Zapisywanie i odczytywanie zawartości obiektu StringGrid.
Jeżeli stworzyłeś jakąś funkcje która realizuje proces wypełniania komórek tabeli danymi z pliku, to pokaż całą funkcję i sposób przepisywanie danych z pliku do tabeli.




Dlaczego zwiększasz maksymalną liczbę wierszy (RowCount) w pętli poprzez dodawanie wartości row? Wynik takiej inkrementacji będzie prawidłowy tylko wtedy, gdy ta zmienna będzie zawierała wartość 1, ani mniej ani więcej, gdyż jak to wynika z Twojego kodu, po pobraniu każdej linii (getline), jak rozumiem, chcesz zwiększyć liczbę wierszy o 1, czyli kod powinien wyglądać tak:
KOD cpp:     UKRYJ  
StringGrid1->RowCount += 1;




Ponieważ tabela przechowuje wartości typu AnsiString lub UnicodeString (zależy od wersji środowiska) do to pobierania danych z pliku, o ile to możliwe lepiej jest posłużyć się tymi typami danych, a nie char, wchar_t, czyli można zastosować np. klasę TStringList lub podobną. Unikniesz konwersji.
Avatar użytkownika
Cyfrowy Baron
Administrator
Administrator
 
Posty: 4716
Dołączył(a): niedziela, 13 lipca 2008, 15:17
Podziękował : 12
Otrzymał podziękowań: 442
System operacyjny: Windows 7 x64 SP1
Kompilator: Embarcadero RAD Studio XE2
C++ Builder XE2 Update 4
SKYPE: cyfbar
Gadu Gadu: 0
    Windows XPFirefox

Re: Wczytanie z pliku do StringGrid

Nowy postprzez duf » poniedziałek, 20 września 2010, 11:07

Plikt otwieram i wczytuję używając wfstream:
Kod: Zaznacz cały
wstring row = 0;
wfstream wfstr;
wfstr.clear();
wfstr.open ( (sciezka + L"lista.txt").c_str() );
wfstr.imbue(locale(".1250",locale::ctype));

I to jest dobrze. Tylko nie rozumiem dlaczego plik zostaje zamknięty jeżeli chcę dodać rzędy do StringGrida:
Kod: Zaznacz cały
while( getline( wfstr, dane, L'\n' ) )
{
   StringGrid1->RowCount = ++row;
}

a odczyt przebiega bez zakłóceń bez tej instrukcji w środku:
Kod: Zaznacz cały
while( getline( wfstr, dane, L'\n' ) )
{
    ++row;
}
Avatar użytkownika
duf
Intelektryk
Intelektryk
 
Posty: 175
Dołączył(a): czwartek, 9 października 2008, 13:02
Podziękował : 17
Otrzymał podziękowań: 2
System operacyjny: Windows 10
Kompilator: XE8
Gadu Gadu: 0
    Windows XPFirefox

Re: Wczytanie z pliku do StringGrid

Nowy postprzez Cyfrowy Baron » poniedziałek, 20 września 2010, 11:44

I to jest dobrze. Tylko nie rozumiem dlaczego plik zostaje zamknięty jeżeli chcę dodać rzędy do StringGrida:


row jest typy wstring, a zmienna RowCount oczekuje typu int, więc nie możesz tego robić w ten sposób. Co Ty właściwie chcesz osiągnąć, zwiększać o jeden liczbę wierszy w tabeli w każdym obiektu pętli? Jeżeli tak to inkrementujesz o 1, a nie o row, czyli:

KOD cpp:     UKRYJ  
while( getline( wfstr, dane, L'\n' ) )
{
   StringGrid1->RowCount += 1;
}


Nigdzie jednak nie podałeś jak wypełniasz tabelę danymi z pliku! :evil: Pobierasz zawartość pojedynczych linii z pliku do zmiennej dane, ale jak przepisujesz z tej zmiennej wartości do tabeli?




Jedyne co robi ten kod:

KOD cpp:     UKRYJ  
while( getline( wfstr, dane, L'\n' ) )
{
    ++row;
}


to inkrementuje wartość zmiennej row w każdym obiegu pętli o row.



Przecież to wszystko można zrobić w prosty sposób:

KOD cpp:     UKRYJ  
String fileName = sciezka + L"lista.txt";
TStringList *fileList = new TStringList();
fileList->LoadFromFile(fileName);

StringGrid1->RowCount = fileList->Count; // tabela będzie miała dokładnie tyle wierszy ile występuje w pliku

/* dalej następuje przepisanie zawartości pliku do tabeli, ale to już zależy od konstrukcji pliku, czyli struktury danych, które się w nim znajdują */
 
Avatar użytkownika
Cyfrowy Baron
Administrator
Administrator
 
Posty: 4716
Dołączył(a): niedziela, 13 lipca 2008, 15:17
Podziękował : 12
Otrzymał podziękowań: 442
System operacyjny: Windows 7 x64 SP1
Kompilator: Embarcadero RAD Studio XE2
C++ Builder XE2 Update 4
SKYPE: cyfbar
Gadu Gadu: 0
    Windows XPFirefox

Re: Wczytanie z pliku do StringGrid

Nowy postprzez duf » poniedziałek, 20 września 2010, 12:05

Oczywiście pomyliłem się. Powinno być:
Kod: Zaznacz cały
unsigned short int row = 0;

Nie muszę wypełniać danymi tabeli z pliku żeby stwierdzić, że odczyt pliku zostaje przerwany z użyciem
Kod: Zaznacz cały
StringGrid1->RowCount = ++row;

a bez tej instrukcji odczyt jest prawidłowy.
Avatar użytkownika
duf
Intelektryk
Intelektryk
 
Posty: 175
Dołączył(a): czwartek, 9 października 2008, 13:02
Podziękował : 17
Otrzymał podziękowań: 2
System operacyjny: Windows 10
Kompilator: XE8
Gadu Gadu: 0
    Windows XPFirefox

Re: Wczytanie z pliku do StringGrid

Nowy postprzez Cyfrowy Baron » poniedziałek, 20 września 2010, 12:10

Błąd nie może wynikać z tego, czy masz wewnątrz pętli:

KOD cpp:     UKRYJ  
++row; // row typu int


czy też:

KOD cpp:     UKRYJ  
StringGrid1->RowCount = ++row;// row typu int


Gdyż obydwa zapisy dadzą ten sam wynik.

Ile wierszy zawiera plik, czyli ile obiegów wykonuje pętla while? Jeżeli wierszy jest kilka tysięcy, to obiekt StringGrid będzie miał problem z inkrementowaniem tabeli o 1 wiersz w każdym obiegu pętli, gdyż należy pamiętać, że ta tabela jest rysowana, a więc na wykonanie operacji polegającej wielokrotnym (kilkutysięcznym) rysowaniu tabeli potrzeba czasu, dlatego, nie należy inkrementować tabeli wewnątrz pętli lecz określić liczbę jej wierszy za jednym razem, a więc tak:

KOD cpp:     UKRYJ  
int row = 0;
while( getline( wfstr, dane, L'\n' ) )
{
   row += 1;
}

StringGrid1->RowCount = row;
Avatar użytkownika
Cyfrowy Baron
Administrator
Administrator
 
Posty: 4716
Dołączył(a): niedziela, 13 lipca 2008, 15:17
Podziękował : 12
Otrzymał podziękowań: 442
System operacyjny: Windows 7 x64 SP1
Kompilator: Embarcadero RAD Studio XE2
C++ Builder XE2 Update 4
SKYPE: cyfbar
Gadu Gadu: 0
    Windows XPFirefox

Re: Wczytanie z pliku do StringGrid

Nowy postprzez duf » poniedziałek, 20 września 2010, 12:35

Cyfrowy Baron napisał(a):Błąd nie może wynikać z tego, czy masz wewnątrz pętli:

KOD cpp:     UKRYJ  
++row; // row typu int


czy też:

KOD cpp:     UKRYJ  
StringGrid1->RowCount = ++row;// row typu int

A jednak wynika. I dlatego zadałem pytanie na tym forum.
Avatar użytkownika
duf
Intelektryk
Intelektryk
 
Posty: 175
Dołączył(a): czwartek, 9 października 2008, 13:02
Podziękował : 17
Otrzymał podziękowań: 2
System operacyjny: Windows 10
Kompilator: XE8
Gadu Gadu: 0
    Windows XPFirefox

Re: Wczytanie z pliku do StringGrid

Nowy postprzez Cyfrowy Baron » poniedziałek, 20 września 2010, 12:37

Uzupełniłem swoją wypowiedź w poprzednim poście, ale przytoczę ją jeszcze raz:

Ile wierszy zawiera plik, czyli ile obiegów wykonuje pętla while? Jeżeli wierszy jest kilka tysięcy, to obiekt StringGrid będzie miał problem z inkrementowaniem tabeli o 1 wiersz w każdym obiegu pętli, gdyż należy pamiętać, że ta tabela jest rysowana, a więc na wykonanie operacji polegającej wielokrotnym (kilkutysięcznym) rysowaniu tabeli potrzeba czasu, dlatego, nie należy inkrementować tabeli wewnątrz pętli lecz określić liczbę jej wierszy za jednym razem, a więc tak:

KOD cpp:     UKRYJ  
int row = 0;
while( getline( wfstr, dane, L'\n' ) )
{
   row += 1;
}

StringGrid1->RowCount = row;
Avatar użytkownika
Cyfrowy Baron
Administrator
Administrator
 
Posty: 4716
Dołączył(a): niedziela, 13 lipca 2008, 15:17
Podziękował : 12
Otrzymał podziękowań: 442
System operacyjny: Windows 7 x64 SP1
Kompilator: Embarcadero RAD Studio XE2
C++ Builder XE2 Update 4
SKYPE: cyfbar
Gadu Gadu: 0
    Windows XPFirefox

Re: Wczytanie z pliku do StringGrid

Nowy postprzez duf » poniedziałek, 20 września 2010, 12:44

Cyfrowy Baron napisał(a):Ile wierszy zawiera plik, czyli ile obiegów wykonuje pętla while?

22
Avatar użytkownika
duf
Intelektryk
Intelektryk
 
Posty: 175
Dołączył(a): czwartek, 9 października 2008, 13:02
Podziękował : 17
Otrzymał podziękowań: 2
System operacyjny: Windows 10
Kompilator: XE8
Gadu Gadu: 0
    Windows XPFirefox

Re: Wczytanie z pliku do StringGrid

Nowy postprzez Cyfrowy Baron » poniedziałek, 20 września 2010, 12:48

Więc nie powinno być błędu w inkrementowaniem tabeli wewnątrz pętli. Prawdopodobnie problem dotyczy zupełnie czegoś innego niż przytoczony tutaj przez Ciebie kod. Czy możesz kompletny cały kod odpowiedzialny za wczytanie danych z pliku razem z plikiem w załączniku?! Bez tego nic więcej się nie da zrobić, gdyż przytoczony kod, nie zawiera błędów.
Avatar użytkownika
Cyfrowy Baron
Administrator
Administrator
 
Posty: 4716
Dołączył(a): niedziela, 13 lipca 2008, 15:17
Podziękował : 12
Otrzymał podziękowań: 442
System operacyjny: Windows 7 x64 SP1
Kompilator: Embarcadero RAD Studio XE2
C++ Builder XE2 Update 4
SKYPE: cyfbar
Gadu Gadu: 0
    Windows XPFirefox

Re: Wczytanie z pliku do StringGrid

Nowy postprzez duf » poniedziałek, 20 września 2010, 12:56

Co tu załączać. Wystarczy wkleić to co napisałem.
Avatar użytkownika
duf
Intelektryk
Intelektryk
 
Posty: 175
Dołączył(a): czwartek, 9 października 2008, 13:02
Podziękował : 17
Otrzymał podziękowań: 2
System operacyjny: Windows 10
Kompilator: XE8
Gadu Gadu: 0
    Windows XPFirefox

Re: Wczytanie z pliku do StringGrid

Nowy postprzez Cyfrowy Baron » poniedziałek, 20 września 2010, 12:57

Chodziło mi raczej o sam plik, by sprawdzić jaką ma konstrukcję.
Avatar użytkownika
Cyfrowy Baron
Administrator
Administrator
 
Posty: 4716
Dołączył(a): niedziela, 13 lipca 2008, 15:17
Podziękował : 12
Otrzymał podziękowań: 442
System operacyjny: Windows 7 x64 SP1
Kompilator: Embarcadero RAD Studio XE2
C++ Builder XE2 Update 4
SKYPE: cyfbar
Gadu Gadu: 0
    Windows XPFirefox

Re: Wczytanie z pliku do StringGrid

Nowy postprzez Cyfrowy Baron » poniedziałek, 20 września 2010, 13:05

Przeprowadziłem test z Twoim kodem na zwykłym pliku tekstowym i u mnie wszystko działa poprawnie.

Testowany kod:

KOD cpp:     UKRYJ  
 #include <fstream.h>
 #include <string>

 int row = 0;
 wfstream wfstr;
 wstring dane;
 wfstr.clear();
 wfstr.open(L"c:\\test.txt");
 wfstr.imbue(locale(".1250",locale::ctype));

 while( getline( wfstr, dane, L'\n' ) )
 {
   StringGrid1->RowCount = ++row;
 }


Skoro kod jest prawidłowy, to błąd może występować tylko w pliku.
Avatar użytkownika
Cyfrowy Baron
Administrator
Administrator
 
Posty: 4716
Dołączył(a): niedziela, 13 lipca 2008, 15:17
Podziękował : 12
Otrzymał podziękowań: 442
System operacyjny: Windows 7 x64 SP1
Kompilator: Embarcadero RAD Studio XE2
C++ Builder XE2 Update 4
SKYPE: cyfbar
Gadu Gadu: 0
    Windows XPFirefox

Re: Wczytanie z pliku do StringGrid

Nowy postprzez polymorphism » poniedziałek, 20 września 2010, 13:27

Może być też tak, że plik ma inne kodowanie niż to, w którym pracuje strumień (cp1250). Przy konwersji ansi -> unikod pojawiają się jakieś kody, których nie ma w danej stronie kodowej, przez co strumień wchodzi w stan błędu (choć nie wiem, czy to jest standardowe zachowanie strumienia).

p.s.1. do zliczania linii w pliku lepiej użyć metody ignore:

KOD cpp:     UKRYJ  
unsigned rows = 0;

while(wfstr.ignore(numeric_limits<streamsize>::max(),L'\n')) ++rows;

wfstr.clear();
wfstr.seekg(0,ios.beg);

/* i tu czytasz od początku */
 


p.s.2.
(...) a więc na wykonanie operacji polegającej wielokrotnym (kilkutysięcznym) rysowaniu tabeli potrzeba czasu

Pamiętam, że ListView miał metody BeginUpdate i EndUpdate, służące do tego, by zablokować odświeżanie kontrolki przy dodawaniu nowych wierszy. Czy StringGrid nie ma czegoś takiego przypadkiem?
C++ Reference - opis wszystkich klas STL-a i funkcji C.
Avatar użytkownika
polymorphism
Doświadczony Programista ● Moderator
Doświadczony Programista ● Moderator
 
Posty: 2156
Dołączył(a): piątek, 19 grudnia 2008, 13:04
Podziękował : 0
Otrzymał podziękowań: 200
System operacyjny: Windows 8.1
Windows 10
Linux Mint 21.1
Kompilator: Visual Studio
Visual Studio Code
MSYS2 (MinGW, clang)
g++
clang
Gadu Gadu: 0
    Windows XPFirefox

Re: Wczytanie z pliku do StringGrid

Nowy postprzez Cyfrowy Baron » poniedziałek, 20 września 2010, 13:34

p.s. do zliczania linii w pliku lepiej użyć metody ignore:


Tutaj chyba chodzi jednak nie tylko o zliczanie linii, lecz również o jednoczesne pobieranie zawartości tej linii i przepisywanie jej do tabeli, chociaż kodu do tego jeszcze nie ma, ale tylko takie założenie uzasadnia użycie getline do określenia ilości wierszy.
Avatar użytkownika
Cyfrowy Baron
Administrator
Administrator
 
Posty: 4716
Dołączył(a): niedziela, 13 lipca 2008, 15:17
Podziękował : 12
Otrzymał podziękowań: 442
System operacyjny: Windows 7 x64 SP1
Kompilator: Embarcadero RAD Studio XE2
C++ Builder XE2 Update 4
SKYPE: cyfbar
Gadu Gadu: 0
    Windows XPFirefox

Następna strona

  • 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 53 gości

cron