Verschiedene StringGrid Instanzen

Für Fragen zur Programmiersprache auf welcher Lazarus aufbaut
Antworten
JeyJey
Beiträge: 9
Registriert: Do 22. Sep 2016, 09:55

Verschiedene StringGrid Instanzen

Beitrag von JeyJey »

Hallo liebe Lazarus-Community.

Ich hoffe ich Poste mein Problem / meine Frage in den richtigen Thread.

Es geht darum, das ich in meinem Programm gerne StringGrids als DatenContainer verwende. Ich habe verschiedene Prozeduren udn Funktionen, welche StringGrids bekommen, mit diesen arbeiten, verändern, zurückgeben.

Nun ist mir etwas aufgefallen. Trotz das ich mit TStringGrid.Creat(nil) unterschiedliche StringGrids erstelle, scheine ich immer auf dem gleichen StringGrid zu operieren. Kleines Beispiel:

Code: Alles auswählen

procedure TForm1.FormCreate(Sender: TObject);
var
  sGrid_1: TStringGrid;
  sGrid_2: TStringGrid;
begin
  eineZahl := 0;
  sGrid_1 := TStringGrid.Create(nil);
  sGrid_2 := TStringGrid.Create(nil);
  sGrid_1.Cells[0,0] := 'TEST';
  sGrid_2 := fillGrid(sGrid_1);
 
  ShowMessage(sGrid_1.Cells[0,0]);
  ShowMessage(sGrid_2.Cells[0,0]);
 
  sGrid_1.Free;
 
  ShowMessage(sGrid_2.Cells[0,0]);
end;
 
function TForm1.fillGrid(grid: TStringGrid):TStringGrid;
begin
  grid.Cells[0,0] := 'Ein anderer Test';
end;       


In folgendem Beispiel habe ich 2 StringGrids erstellt. Ich habe in der Funktion extra kein var verwendet. Es ist also ein Call by Value und kein Call by Reference. Das heißt, es sollte eigentlich lediglich eine Wertübergabe statt finden. Trotzdem scheinen beide StringGrids ein und das selbe Objekt zu sein und ich verstehe das nicht. Vielleicht ist das StringGrid für mein Vorhaben auch gar nicht geeignet und ich zweckentfremde es hier. Falls dem so ist, kann mir jemand ein anderen ähnlichen Container vorschlagen in dem ich Daten ähnlich wie in einem StringGrid speichern kann?


Gruß

JeyJey

Mathias
Beiträge: 6194
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: Verschiedene StringGrid Instanzen

Beitrag von Mathias »

Bei deiner Funktion fillGrid, übergibst du nur den Pointer, wo sich deine grid befindet und keine Kopie der Ganzen grid, somit wird deine StringGrid verändert.

So nebenbei, liefert deine function fillGrid kein kein Ergebnis zurück. Hat dein Kompiler keine Warnung ausgegeben ?

Noch ein kleines Detail, ändere dein nil in Create auf Self.

Code: Alles auswählen

sGrid_1 := TStringGrid.Create(nil); // alt
sGrid_1 := TStringGrid.Create(Self)// neu

Somit wird der Speicher am Ende frei gegeben und es liegen keine Leichen rum.


Falls dem so ist, kann mir jemand ein anderen ähnlichen Container vorschlagen in dem ich Daten ähnlich wie in einem StringGrid speichern kann?

Hast du mal TStringList angeguckt ?
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

JeyJey
Beiträge: 9
Registriert: Do 22. Sep 2016, 09:55

Re: Verschiedene StringGrid Instanzen

Beitrag von JeyJey »

Jetzt wo du es sagst, stimmt, da fehlt ein result := ...

Eigentlich dachte ich, ich übergebe eine Kopie und nicht den Pointer. Dachte wenn var davor steht ist es Call by Reference und ich übergebe den Pointer?

Muss ich dann const davor packen oder wie übergebe ich "nur" eine Kopie des StringGrids? :)

Ja TStringList hab ich mal angeschaut, würde auch gehen, aber das StringGrid wäre doch schon passender :)

Das heißt, wenn ich anstelle von nil self nehme brauch ich auch kein .Free oder .Destroy? Sobald die Form quasi geschlossen wird wird aufgeräumt?

PS: gerade noch mit var und const in meiner Funktion versucht. Dennoch nicht das gewünschte Ergebnis. Anscheinend wird jedes mal das Objekt an sich also der Pointer mit übergeben

Mathias
Beiträge: 6194
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: Verschiedene StringGrid Instanzen

Beitrag von Mathias »

Das heißt, wenn ich anstelle von nil self nehme brauch ich auch kein .Free oder .Destroy? Sobald die Form quasi geschlossen wird wird aufgeräumt?

Genau.

Ich verstehe deine Frage nicht richtig, aber wen du den Inhalt kopieren willst, dann kann man dies so machen:

Code: Alles auswählen

  StringGrid1.Cells[0,0]:= 'a';
  StringGrid2.Assign(StringGrid1);
  StringGrid1.Cells[0,0]:= 'b';   

Zur Vereinfachung habe ich dazu 2 Grids aus der Komponenten-Leiste aufs Form gezogen.
Ist wahrscheinlich für deine Versuche auch einfacher und wen sie später nicht sichtbar sein sollen, macht einfache.

Code: Alles auswählen

StringGrid1.visible := false;
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

JeyJey
Beiträge: 9
Registriert: Do 22. Sep 2016, 09:55

Re: Verschiedene StringGrid Instanzen

Beitrag von JeyJey »

Ahhh perfekt. mit assign (also kopieren des StringGrid-Inhaltes geht es nun)

Aber ich verstehe immer noch nicht, wieso es nicht möglich ist ein Objekt nur als Kopie und nicht als Pointer in einer Funktion zu übergeben.

Also ich muss ja quasi durch assign erzwingen, das der Inhalt des StringGrid_1 in das StringGrid_2 kopiert wird.

Wenn ich das ganze jetzt z.B. mit integer mache und etwas wie die Art:

Code: Alles auswählen

 
procedure TForm1.FormCreate(Sender: TObject);
var
  eineZahl: integer;
  eineAndereZahl : integer;
begin
   eineZahl := 5;
   eineAndereZahl := add(eineZahl);
 
   ShowMessage(IntToStr(eineZahl));
   ShowMessage(IntToStr(eineAndereZahl));
end;   
 
function TForm1.add(zahl : integer):integer;
begin
  zahl := zahl + 5;
  result := zahl;
end;   
 
 


Hier wurde nun nur der Wert übergeben. Der Inhalt von eineZahl ändert sich nie, bleibt also 5.

Würde ich aber function TForm1.add(var zahl : integer):integer; schreiben, würde sich der Wert von eineZahl auch auf 10 ändern. Und ich verstehe nicht, wieso dies bei StringGrids nicht auch so funktioniert. Das ich also nur eine Kopie des StringGrids übergebe, damit irgendetwas anstelle, aber das Original nicht verändere.

Mathias
Beiträge: 6194
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: Verschiedene StringGrid Instanzen

Beitrag von Mathias »

Aber ich verstehe immer noch nicht, wieso es nicht möglich ist ein Objekt nur als Kopie und nicht als Pointer in einer Funktion zu übergeben.

Weil eine Klasse viel komplexer ist als nur ein einfacher Integer. Der Compiler müsste die ganz Klasse mit Create erzeugen und anschliesend alles kopieren.

So etwas geht,

Code: Alles auswählen

procedure TForm1.Button1Click(Sender: TObject);
var
  grid: TStringGrid;
begin
  grid := test(StringGrid1);
  ShowMessage(grid.Cells[1, 1]);
  grid.Free;
end;
 
function TForm1.test(grid: TStringGrid): TStringGrid;
begin
  Result := TStringGrid.Create(nil);
  Result.Assign(grid);
  Result.Cells[1, 1] := 'abc';
end

Da siehst du, da in der Kopie etwas geändert wurde, aber da Orignal nicht verändert würde.
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

JeyJey
Beiträge: 9
Registriert: Do 22. Sep 2016, 09:55

Re: Verschiedene StringGrid Instanzen

Beitrag von JeyJey »

Alles klar, vielen vielen dank für die Erklärung. Ich denke jetzt ist mir einiges klarer. Eine Frage hätte ich aber abschließend noch.


Code: Alles auswählen

function TForm1.test(grid: TStringGrid): TStringGrid;
begin
  Result := TStringGrid.Create(nil);
  Result.Assign(grid);
  Result.Cells[1, 1] := 'abc';
end;


Wie sieht es hier mit dem Objekt von Result aus? Es wird ja ein neues StringGrid erstellt und dem Result zugewiesen, danach werden die Daten von grid nach Result kopiert und das ist dann der Rückgabewert. Aber wie sieht es hier mit dem frei machen von dem StringGrid was nun an Result gebunden ist aus?

Also in der Main wird ja dann grid.Free gemacht. Muss man dies für Result nicht tun? Weil was wenn ich die Funktion test nun mehrmals aufrufe, sagen wir 3 mal, tümpeln dann 3 mal irgendwo StringGrids im Speicher rum oder werden die, nach dem der Rückgabewert getätigt wurde automatisch wieder frei gegeben?

Benutzeravatar
m.fuchs
Lazarusforum e. V.
Beiträge: 2640
Registriert: Fr 22. Sep 2006, 19:32
OS, Lazarus, FPC: Winux (Lazarus 2.0.10, FPC 3.2.0)
CPU-Target: x86, x64, arm
Wohnort: Berlin
Kontaktdaten:

Re: Verschiedene StringGrid Instanzen

Beitrag von m.fuchs »

JeyJey hat geschrieben:Muss man dies für Result nicht tun? Weil was wenn ich die Funktion test nun mehrmals aufrufe, sagen wir 3 mal, tümpeln dann 3 mal irgendwo StringGrids im Speicher rum oder werden die, nach dem der Rückgabewert getätigt wurde automatisch wieder frei gegeben?

Die musst du natürlich per Hand freigeben. Automatisch wird da nichts gemacht, solange du nil im .Create übergibst. Aber warum willst du das überhaupt machen, was du da machst?
Software, Bibliotheken, Vorträge und mehr: https://www.ypa-software.de

Mathias
Beiträge: 6194
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: Verschiedene StringGrid Instanzen

Beitrag von Mathias »

Wie sieht es hier mit dem Objekt von Result aus? Es wird ja ein neues StringGrid erstellt und dem Result zugewiesen, danach werden die Daten von grid nach Result kopiert und das ist dann der Rückgabewert. Aber wie sieht es hier mit dem frei machen von dem StringGrid was nun an Result gebunden ist aus?

Der Rückgabe Wert der Funktion test ist auch nur ein Pointer auf die neu erstellte grid. Somit muss es in der main frei gegeben werden.

Das ist der gleiche Effekt, wie bei der Funktion FindAllFiles(...), dort ist das Create auch in der Funktion, aber um die Freigabe muss man sich dann selbst kümmern,
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

Antworten