Verschiedene StringGrid Instanzen

Für Fragen zur Programmiersprache auf welcher Lazarus aufbaut

Verschiedene StringGrid Instanzen

Beitragvon JeyJey » 23. Feb 2017, 17:52 Verschiedene StringGrid Instanzen

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
JeyJey
 
Beiträge: 9
Registriert: 22. Sep 2016, 08:55

Beitragvon Mathias » 23. Feb 2017, 18:12 Re: Verschiedene StringGrid Instanzen

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 gün
Mit Java und C/C++ sehe ich rot
Mathias
 
Beiträge: 4343
Registriert: 2. Jan 2014, 17:21
Wohnort: Schweiz
OS, Lazarus, FPC: Linux (die neusten Trunc) | 
CPU-Target: 64Bit
Nach oben

Beitragvon JeyJey » 23. Feb 2017, 18:25 Re: Verschiedene StringGrid Instanzen

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
JeyJey
 
Beiträge: 9
Registriert: 22. Sep 2016, 08:55

Beitragvon Mathias » 23. Feb 2017, 18:37 Re: Verschiedene StringGrid Instanzen

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 gün
Mit Java und C/C++ sehe ich rot
Mathias
 
Beiträge: 4343
Registriert: 2. Jan 2014, 17:21
Wohnort: Schweiz
OS, Lazarus, FPC: Linux (die neusten Trunc) | 
CPU-Target: 64Bit
Nach oben

Beitragvon JeyJey » 23. Feb 2017, 18:55 Re: Verschiedene StringGrid Instanzen

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.
JeyJey
 
Beiträge: 9
Registriert: 22. Sep 2016, 08:55

Beitragvon Mathias » 23. Feb 2017, 19:50 Re: Verschiedene StringGrid Instanzen

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 gün
Mit Java und C/C++ sehe ich rot
Mathias
 
Beiträge: 4343
Registriert: 2. Jan 2014, 17:21
Wohnort: Schweiz
OS, Lazarus, FPC: Linux (die neusten Trunc) | 
CPU-Target: 64Bit
Nach oben

Beitragvon JeyJey » 24. Feb 2017, 11:47 Re: Verschiedene StringGrid Instanzen

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?
JeyJey
 
Beiträge: 9
Registriert: 22. Sep 2016, 08:55

Beitragvon m.fuchs » 24. Feb 2017, 13:07 Re: Verschiedene StringGrid Instanzen

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
m.fuchs
Lazarusforum e. V.
 
Beiträge: 2064
Registriert: 22. Sep 2006, 18:32
Wohnort: Berlin
OS, Lazarus, FPC: Winux (Lazarus 2.0, FPC 3.0.4) | 
CPU-Target: x86, x64, arm
Nach oben

Beitragvon Mathias » 24. Feb 2017, 18:19 Re: Verschiedene StringGrid Instanzen

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 gün
Mit Java und C/C++ sehe ich rot
Mathias
 
Beiträge: 4343
Registriert: 2. Jan 2014, 17:21
Wohnort: Schweiz
OS, Lazarus, FPC: Linux (die neusten Trunc) | 
CPU-Target: 64Bit
Nach oben

• Themenende •

Zurück zu Freepascal



Wer ist online?

Mitglieder in diesem Forum: 0 Mitglieder und 4 Gäste

porpoises-institution
accuracy-worried