odczyt dwóch tablic strumieniami i spr., który przycis

0

Witam. Mam dwa problemy:

Piszę program, do tworzenia map. Napotkałem probelm z odczytem zapisanej mapy. Zapisują i odzczytuje ją strumieniami. Zaprezentuję deklarację tablic, które zapisuje oraz procedury odczytu i zapisu mapy:

// te dwie tablice właśnie zapisuje
// podczas tworzenie mapy tablicy Mapa przydzielana jest pamieć i są do niej wpisywane wartości
Mapa : array of array of Integer ;
Informacje : array [0..4] of Integer ;

// tą procką zapsiuje mapę:

procedure TGlowna.Zapiszmap1Click(Sender: TObject);
var
FileStream : TFileStream ;
begin
if SaveDialog.Execute then
begin
Informacje[0] := szer_kafelka ;
Informacje[1] := wys_kafelka ;
Informacje[2] := szer_mapy ;
Informacje[3] := wys_mapy ;

     if not FileExists(SaveDialog.FileName) then
        FileStream := TFileStream.Create(SaveDialog.FileName , fmCreate)
     else FileStream := TFileStream.Create(SaveDialog.FileName , fmOpenWrite) ;

         FileStream.WriteBuffer(Informacje, SizeOf(Informacje)) ;
         FileStream.Seek(SizeOf(Mapa) , soFromEnd) ;
         FileStream.Free ;
end ;

end;

// a tą procedurą odczytuje:
// co niepotrzebne to pominąłem
procedure TGlowna.Otwrzmap1Click(Sender: TObject);
var
FileStream : TFileStream ;
begin
if OpenDialog.Execute then
begin
FileStream := TFileStream.Create(OpenDialog.FileName , fmOpenRead);

 FileStream.ReadBuffer(Informacje, SizeOf(Informacje));
 SetLength(Mapa , (Informacje[2] div Informacje[0]), (Informacje[3]div Informacje[1])) ;
 FileStream.ReadBuffer(Mapa, SizeOf(Mapa));

 end;

end ;

Jak odczytuje to wywala mi błąd : "Stream read error". Opisze może po kolei co ma się stać z tablicą Mapa, więc tak: najpierw wczytuje tablicę Informacje, potem na podstawie danych z tej tablicy przydzielamy pamięć dla naszej tablicy Mapa, a potem wczytujemy jej zawartość z pliku. Wiecie może co jest nie tak? Jak odczytać tą drugą tablicę(Mapa), bo tablicę Informacje odczytuje poprawnie ?

Oto drugie pytanko:
[dopisane] to już nieaktualne, pomóżcie z tym wyżej :-)
Piszę także sapera. Plansza zbudowana jest z dynamicznie stworzonych TSpeedButton'ów. A problem mam taki, że nie wiem jak sprawdzić, który prycisk został wciśnięty, żeby sprawdzić, czy nie mam on wartości 0(jeżeli tak, to odkrywane są pola na około). Próbowałem obliczać to na podstawie położenia myszki(OnMouseMove panelu, na którym są pola) szybko się skapowałem, że przecież te pola zasłaniają ów panel :|. Macie jakiś pomysł, jak to sprawdzać? Może coś z Senderem? Sam już nie wiem ;p. Dodam tylko, że pola mam w tablicy dwuwymiarowej:

Pola : array of array of TSpeedButton ;

Dzięki za wszelkie odpowiedzi, pozdro...

0

SAPER :

możesz to zrobić w ten sposób. Jeśli button jest pusty to daj mu taga 0 [jesli ma 4 punkty - 4 -> bedzie prosciej] i potem:

for i:=0 to frmMain.ComponentCount -1 do
begin
if (frmMain.Components[j] is TSpeedButton) and ((frmMain.Components[j] as TSpeedButton).<font color="red">Tag=0</span>) then
begin
>..............>.............>
end;
end;

[diabel] na razie [diabel]

0

No dobra, ale jak mam sprawdzić, który przycisk został kliknięty ?

0

Rozmiar kazdej tablicy dynamicznej (a więc także SizeOf(Mapa)) jest rowny wielkosci wskaznika, czyli 4.

0

Nieznam się na niczym ale, wydaje mi się że rozmiar tablicy dynamicznej zwraca funkcja Length(NazwaTablicy).

0

Oki, ale ja wciąż nie wiem co zrobić, żeby poprawnie zapisać tą drugą, dynamiczną tablicę, a potem ją odczytać [glowa] Weźcie pomóżcie...

[dopisane] poradziłem sobie już z tym Saperem - dzięki the.riddle. Jednak wciąż mam problem z odczytem tej drugiej tablicy... ;-)

0

Niechce mi się sprawdzać lecz myślę, że to Ci może pomóc.

Zapis:

FileStream.WriteBuffer(Informacje, SizeOf(Informacje));
FileStream.WriteBuffer(Mapa, SizeOf(Integer)*Length(Mapa))

Odczyt:

FileStream.ReadBuffer(Informacje, SizeOf(Informacje));
Rozmiar:= (twoje obliczenia rozmiaru);
SetLength(Mapa, Rozmiar);
FileStream.ReadBuffer(Mapa, SizeOf(Integer)*Length(Mapa));

0

Niechce mi się sprawdzać lecz myślę, że to Ci może pomóc.

Wydaje mi się, że to dobra droga, aczkolwiek Mapa to array of array, więc w ten sposób zapisane zostaną wskaźniki do podtablic (czyli wierszy).

Proponuję zapisać Length(Mapa), następnie Length(Mapa[0]), Length(Mapa[1]) itd, a potem zawartości kolejnych wierszy o długościach Length(Mapa[0])*SizeOf(Integer) itd. Ewentulanie przeplatając długości z zawartościami.

Aha, i ja bym użył LongInt a nie Integer. Bo za 2 lata skompilujesz program w 64bit systemie, Integer będzie miał 64b i odczyt z pliku się zkaszani.

0

Za dwa lata (o ile będzie jeszcze musiał to przerabiać) napisze:
type Integer = LongInt; i będzie wszystko grać, bo jeżeli zmieni się domyślny typ na 64-bit, to także większość modułów Delphi będzie musiała zostać zmieniona, bo jest używane Integer.
Zresztą jakoś w C sobie z tym radzą, skoro jest w standardzie int, ale nie ma określonego jego rozmiaru. Stawia się na teoretycznie większą szybkość, jeżeli użyje się domyślnego rozmiaru dla danej platformy. Choć IMHO lepiej by było na sztywno ustalić rozmiary typów danych, aby właśnie takich problemów z kompatybilnością nie było (Integer 16-bit i 32-bit, Real 48-bit i 32-bit).

0

Mam jeszcze jedną prośbę, pq, mogłbyś załączyć chociaż garstkę kodu ? [hurra] Bo nie za bardzo wiem, jak wykorzystać to, co mi napisałeś. Będe bardzo wdzięczny [hurra]

0

Weź pomóż, pq...

0

Weź pomóż, pq...

No dobra. Ale nie strumieniami bo lubię staromodne metody. Jak chcesz, to przerób.

type
  TDynamic2DIntArray= array of array of Integer;

{definicja konieczna by parametr procedury ładującej był traktowany jako
tablica dynamiczna, a nie otwarty parametr tablicowy.  Mówiąc po ludzku, żeby można było używać SetLength}


procedure Load2DIntArray(var IArray: TDynamic2DIntArray;
                          const FileName: TFileName);
var
 F: file of Integer;
 i, l: Integer;
begin
 AssignFile(F, FileName);
 Reset(F);
 Read(F, l);
 SetLength(IArray, l);
 for i:=0 to Pred(Length(IArray)) do
 begin
   Read(F, l);
   SetLength(IArray[i], l);
   BlockRead(F, IArray[i][0], l);
 end;
 CloseFile(F);
end;

procedure Save2DIntArray(const IArray: TDynamic2DIntArray;
                          const FileName: TFileName);
var
 F: file of Integer;
 i, l: Integer;
begin
 AssignFile(F, FileName);
 Rewrite(F);
 l:=Length(IArray);
 Write(F, l);
 for i:=0 to Pred(Length(IArray)) do
 begin
   l:=Length(IArray[i]);
   Write(F, l);
   BlockWrite(F, IArray[i,0],l);
 end;
 CloseFile(F);
end;

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