Entwickler-Ecke

Grafische Benutzeroberflächen (VCL & FireMonkey) - Übertragen einer Reihe von einem StringGrid in ein anderes


Peter18 - Do 12.01.12 18:23
Titel: Übertragen einer Reihe von einem StringGrid in ein anderes
Ein freundliches Hallo an alle,

ich hoffe jemand kann folgenden Effekt erklären:

Ich möchte den Inhalt bestimmter Reihen eines StringGrids in ein anderes übertragen. Natürlich kann ich in einer Schleife Zelle für Zelle übertragen. Eleganter ist es aber eine ganze Zeile als CommaText zu übertragen. Einlesen aus einer Datei (CommaText) und speichern klappt hervorragend.

Wenn ich aber

Delphi-Quelltext
1:
Grid2.Rows[I2].CommaText := Grid1.Rows[I1].CommaText;                    

zuweise, werden leere Zellen mit dem Inhalt der nächsten nicht leeren Zelle gefüllt. Auch der Umweg über eine Stringvariable funktioniert nicht. Ebensowenig Copy. Es bleibt bei dem Ergebnis: Die Daten rücken auf und die Zellen am Ende bleiben leer. Es sieht so aus, als ob die Kommata herausgefiltert werden.

Kann jemand Helfen? Dank Euch im voraus, auch fürs Bemühen

Grüße
Peter


Tranx - Do 12.01.12 19:08

Hallo, ich habe es getestet, bei mir funktioniert das wie gewünscht.


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
unit testUebertrag;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  StdCtrls, Grids;

type
  TForm1 = class(TForm)
    StringGrid1: TStringGrid;
    StringGrid2: TStringGrid;
    buuebertrag: TButton;
    procedure buuebertragClick(Sender: TObject);
  private
    { Private-Deklarationen }
  public
    { Public-Deklarationen }
  end;

var
  Form1: TForm1;

implementation

{$R *.DFM}

procedure TForm1.buuebertragClick(Sender: TObject);
var
  i : integer;
begin
   for i := 0 to 4 do
     Stringgrid2.Rows[i].CommaText := Stringgrid1.Rows[i].Commatext;
end;

end.


Es werden die Einträge der einzelnen Zellen exakt 1 zu 1 übertragen. Hätte ich auch bei der Eigenschaft Kommatext nicht anders erwartet, da sie zu der TStrings-Komponente (u.a. Rows) gehört. P.S. ich habe Delphi 5.


jaenicke - Do 12.01.12 20:15

Die Fragestellung klingt nach einem typischen Fall von einer GUI, die gleichzeitig als Datenspeicher missbraucht wird...

Wenn du die Daten im Hintergrund in geeigneten Datenstrukturen halten würdest, könntest du auch direkt damit arbeiten statt mit dem TStringGrid. Und wenn du es dir ganz einfach machenn willst, nimm einfach die VirtualTrees. Die sind schneller, sehen besser aus, ...

// EDIT:
Gibt es eigentlich nur CommaText und nicht auch direkt Text? :gruebel:


Tranx - Fr 13.01.12 09:19

Trotz allem verstehe ich nicht, wieso das bei mir - bei einem einfachen Programm, dass ich eben mal schrieb - ohne Probleme klappte, und bei ihm scheinbar nicht. Vielleicht wäre da mehr Info sinnvoll, um den Fehler einzugrenzen. Und es kann ja sein, dass er das Stringgrid für Eingaben benötigt, welche im Programm erfolgen, und die dann übertragen werden. Wenn alles in Datenstrukturen alleine verarbeitet wird, wozu benötigt man dann noch TStringgrid? Manche Anwendungen haben eben keine durchgehend gleiche Datenstruktur. Da kann es schon sein, dass ein Stringgrid sinnvoll ist. Aber unabhängig davon - die Frage ist doch - inwieweit diese Diskrepanz erklärbar ist.


jaenicke - Fr 13.01.12 09:48

user profile iconTranx hat folgendes geschrieben Zum zitierten Posting springen:
Wenn alles in Datenstrukturen alleine verarbeitet wird, wozu benötigt man dann noch TStringgrid?
Zur Eingabe und Anzeige. Ausschließlich dafür sind visuelle Komponenten da.

Bei mir funktioniert es aber auch problemlos.

Nichtsdestotrotz stellt sich die Frage warum dieser umständliche Weg sein muss... Egal ob man nun findet, dass das eleganter aussieht oder nicht, sehr langsam ist es in jedem Fall. Denn hier wird erst in CommaText ein String mit Kommata zusammengebastelt, dann beim Zuweisen der Inhalt der Zeile gelöscht, die Zelleninhalte auseinanderklamüsert und wieder in die Zellen eingefügt.

Stattdessen wäre es viel einfacher direkt die einzelnen Strings den Zellen (sprich Einträgen der Stringliste der Zeile) zuzuweisen. Das geht viel schneller und sieht auch für meine Begriffe eleganter aus:

Delphi-Quelltext
1:
Grid2.Rows[I2].Assign(Grid1.Rows[I1]);                    


Peter18 - Fr 13.01.12 11:55

Hallo,

Dank euch allen!

Hallo Tranx, ganz verstehe ich es auch nicht, aber ich vermute, dass es mit der Länge des Strings zusammen hängt. In diesem Fall sind auch mehrere Pfade auf Dateien enthalten und damit ist die Summe der Zeichen größer 255. Dennoch kann ich die Daten aus einer Datei lesen und dem Grid ohne eigene Auswertung als CommaText zuweisen. Die Daten stehen dann in den richtigen Zellen.

Hallo jaenicke,
jaenicke hat folgendes geschrieben:
Die Fragestellung klingt nach einem typischen Fall von einer GUI, die gleichzeitig als Datenspeicher missbraucht wird...

in diesem Fall dient das Grid zur Anzeige und Bearbeitung, aber auch zum zwischenspeichern. Assign funktioniert einwandfrei! Werden die Strings dabei kopiert, oder nur ein Pointer eingetragen?

Du erwähntest VirtualTrees. Die habe ich bei Delphi 4 noch nicht gesehen.

Eine Lösung habe ich jetzt, würde nur gern verstehen, warum dieser Effekt auftritt.

Grüße von der Nordsee

Peter


jaenicke - Fr 13.01.12 12:57

user profile iconPeter18 hat folgendes geschrieben Zum zitierten Posting springen:
Assign funktioniert einwandfrei! Werden die Strings dabei kopiert, oder nur ein Pointer eingetragen?
Die Strings werden kopiert. Aber in neueren Delphiversionen zumindest werden dabei keine weiteren Stringoperationen ausgeführt, da eine TStringList intern nur ein Array von Records mit jeweils der Zeile (bzw. ggf. Name und Wert der Zeile) und dem zugeordneten Objekt ist.

user profile iconPeter18 hat folgendes geschrieben Zum zitierten Posting springen:
Du erwähntest VirtualTrees. Die habe ich bei Delphi 4 noch nicht gesehen.
Ok, da habe ich nicht drauf geachtet, für so alte Delphiversionen gibt es die wohl kaum. Da fehlen dann doch viel zu viele Features, die man da erst nachbauen müsste.

user profile iconPeter18 hat folgendes geschrieben Zum zitierten Posting springen:
Eine Lösung habe ich jetzt, würde nur gern verstehen, warum dieser Effekt auftritt.
Da bleibt nur für das Projekt Debug-DCUs zu aktivieren und zu debuggen was da passiert. Vielleicht ist es ein Fehler in Delphi 4. :nixweiss:
Sieht der String für die Zeilen denn noch korrekt aus?


Narses - Fr 13.01.12 14:53

Moin!

user profile iconjaenicke hat folgendes geschrieben Zum zitierten Posting springen:
user profile iconPeter18 hat folgendes geschrieben Zum zitierten Posting springen:
Assign funktioniert einwandfrei! Werden die Strings dabei kopiert, oder nur ein Pointer eingetragen?
Die Strings werden kopiert. Aber in neueren Delphiversionen zumindest werden dabei keine weiteren Stringoperationen ausgeführt, da eine TStringList intern nur ein Array von Records mit jeweils der Zeile (bzw. ggf. Name und Wert der Zeile) und dem zugeordneten Objekt ist.
Also dass die Strings auf dem Heap dupliziert werden (=weiterer Speicher alloziert wird) glaube ich erst, wenn ich den Assembler-Dump gesehen habe. AFAIR wird in jeder Delphi-Version mit langen Strings nur der Referenz-Zähler erhöht (deshalb gibt es ja UniqueString als Funktion). :| Ich glaube, da schlägt bei dir mal eher wieder die "alte Delphi-Version"-Aversion zu... :zwinker:

cu
Narses


Peter18 - Fr 13.01.12 15:43

Hallo jaenicke, hallo Narses,

Dank euch beiden!

jaenicke hat folgendes geschrieben:
Sieht der String für die Zeilen denn noch korrekt aus?

Ich habe den CommaText einer Variablen zugewiesen und die sah einwandfrei aus. Seltsamer Weise klappt es auch beim Einlesen aus einer Datei. Nur von Grid zu Grid tritt dieser Effekt auf. Werd dann wohl mal in die Assembler-Gruften hinabsteigen müssen, wenn ich mal etwas Zeit habe.

Falls es jemand vor mir tut bin ich für eine Info dankbar.

Güße von der Nordsee im April (oder ist doch noch Januar?)

Peter


jaenicke - Fr 13.01.12 17:49

user profile iconPeter18 hat folgendes geschrieben Zum zitierten Posting springen:
Werd dann wohl mal in die Assembler-Gruften hinabsteigen müssen, wenn ich mal etwas Zeit habe.
Hast du eine Delphiversion ohne Quelltexte? Sonst könntest du mit Debug-DCUs dort schauen.

user profile iconNarses hat folgendes geschrieben Zum zitierten Posting springen:
Also dass die Strings auf dem Heap dupliziert werden (=weiterer Speicher alloziert wird) glaube ich erst, wenn ich den Assembler-Dump gesehen habe. AFAIR wird in jeder Delphi-Version mit langen Strings nur der Referenz-Zähler erhöht (deshalb gibt es ja UniqueString als Funktion). :| Ich glaube, da schlägt bei dir mal eher wieder die "alte Delphi-Version"-Aversion zu... :zwinker:
Ich habe es gerade erst mit XE ausprobiert (nix mit alten Versionen). Im Grunde war es dieser Code:

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
var
  a, b: string;
begin
  a := 'test';
  b := a;
  ShowMessage(a);
  ShowMessage(b);
end;
Der Referenzzähler blieb -1 und es waren zwei verschiedene Pointer. Das habe ich nicht weiter verfolgt, aber es war so. :nixweiss:
Was schlecht war, weil ich gerade jemandem zeigen wollte, dass intern nur der Referenzzähler erhöht wird. Wurde er aber nicht. Mag an den lokalen Variablen liegen.