| Autor |
Beitrag |
Alpha_Wolf
      
Beiträge: 297
Ubuntu, Win XP, Win Vista
C#, Delphi 6 Prof, Delphi 2007 Prof, Java
|
Verfasst: Do 08.12.05 11:32
Ich steh grad irgendwie etwas aufm Schlauch.. Ich habe Eine Liste und einen Record und diesen würd ich gerne mit einer Funktion an eine andere Unit übergeben.
Das hier ist mein Record und meine Liste.
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13:
| type TTreeListRecord = record ColValue0: string; ColValue1: string; end;
... private fTreeListRecord: ^TTreeListRecord; fTreeList: TList;
... SetData(fTreeList, fTreeListRecord); |
Wenn ich jetzt in der anderen Unit das gleiche deklariere bringt er mir entweder eine AccessViolation oder es lässt sich gar nicht kompilieren. Die Liste überträgt er.. aber den Record mit den Pointern nicht..
Ich müsste die Liste und den Record übergeben.. Nachfolgend der Code der anderen Unit:
Delphi-Quelltext 1: 2: 3: 4: 5: 6:
| function TChecklistePrintProcessMgr.SetData(aTreeList: TList; aTreeListRecord: TTreeListRecord): boolean; begin fTreeList := aTreeList; fTreeListRecord := aTreeListRecord; ... |
Ich möchte deswegen die Liste und den Record übergeben weil in der anderen Unit damit weitergearbeitet wird...
Kann mir da jemand weiterhelfen?
Hoffe das war verständlich..^^
Danke.
Edit: Schreibfehler in Code angepasst.
_________________ Diskutiere nie mit einem Irren - er zieht dich auf sein Niveau und schlägt dich mit seiner Erfahrung.
Zuletzt bearbeitet von Alpha_Wolf am Do 08.12.05 11:46, insgesamt 1-mal bearbeitet
|
|
opfer.der.genauigkeit
      
Beiträge: 754
Erhaltene Danke: 1
|
Verfasst: Do 08.12.05 11:41
Hi,
du versucht einen Record vom Typ TTreeListRecord an eine Funktion zu übergeben, die einen Record von Typ TRecord erwartet.
_________________ Stellen Sie sich bitte Zirkusmusik vor.
|
|
Alpha_Wolf 
      
Beiträge: 297
Ubuntu, Win XP, Win Vista
C#, Delphi 6 Prof, Delphi 2007 Prof, Java
|
Verfasst: Do 08.12.05 11:45
Oh.. stimmt.. war allerdings n Schreibfehler.. sorry!
Delphi-Quelltext 1: 2: 3: 4: 5: 6:
| function TChecklistePrintProcessMgr.SetData(aTreeList: TList; aTreeListRecord: TTreeListRecord): boolean; begin fTreeList := aTreeList; fTreeListRecord := aTreeListRecord; ... |
Selbst wenn ich beim Aufruf der Funktion
Delphi-Quelltext 1:
| SetData(fTreeList, fTreeListRecord^); |
mache sagt der Compiler mir:
Quelltext 1:
| Inkompatible Typen: 'Unit1.TTreeListRecord' und 'Unit2.TTreeListRecord' |
Hm.. sag ja ich steh aufm Schlauch -.-
_________________ Diskutiere nie mit einem Irren - er zieht dich auf sein Niveau und schlägt dich mit seiner Erfahrung.
|
|
Gausi
      
Beiträge: 8553
Erhaltene Danke: 479
Windows 7, Windows 10
D7 PE, Delphi XE3 Prof, Delphi 10.3 CE
|
Verfasst: Do 08.12.05 11:49
Du hast TTreeListRecord aber nicht in beiden Units deklariert, oder?
_________________ We are, we were and will not be.
|
|
Alpha_Wolf 
      
Beiträge: 297
Ubuntu, Win XP, Win Vista
C#, Delphi 6 Prof, Delphi 2007 Prof, Java
|
Verfasst: Do 08.12.05 11:55
Sollte ich das nicht? Ich bin grad etwas durchn Wind.. aber woher sollte dann Unit2 wissen was in Unit1 ist? Nur Unit1 weiss was in Unit2 ist..
Ich weiss das doppelte Namensgebung nicht unbedingt gut ist..
Theoretisch könnte ich doch dann einfach Unit1 mit Unit2 bekannt machen und umgekehrt
und den Record und die Liste einmal ins public von Unit1 schreiben.. Ist aber denke ich nicht die Ideallösung..
_________________ Diskutiere nie mit einem Irren - er zieht dich auf sein Niveau und schlägt dich mit seiner Erfahrung.
|
|
petergensfeld
      
Beiträge: 46
Windows Vista 32-Bit
Delphi XE Professional
|
Verfasst: Do 08.12.05 11:59
Hallo Alpha_Wolf,
wenn ich das richtig interpretiere, definierst Du fTreeList in Unit1 als private Klassenvariable. Diese übergibst Du dann per Referenz an eine 2. Klasse (TChecklistePrintProcessMgr), in der Du wieder eine fTreeList als Klassenvariable definierst, richtig? Das halte ich schon mal für keine gute Idee, denn damit würdest Du die Referenz in TChecklistePrintProcessMgr zerschießen, sobald die Klasse in Unit1 zerstört wird. Entweder solltest Du die ganze Liste mit fTreeList.Assign(aTreeList) kopieren oder nur temporär mit der Referenz arbeiten.
Bzgl. der Fehlermeldung: Hast Du TTreeListRecord in Unit2 erneut definiert?
Gruß Dirk
|
|
Gausi
      
Beiträge: 8553
Erhaltene Danke: 479
Windows 7, Windows 10
D7 PE, Delphi XE3 Prof, Delphi 10.3 CE
|
Verfasst: Do 08.12.05 11:59
Alpha_Wolf hat folgendes geschrieben: | | Sollte ich das nicht? |
Nein, sollte man nicht. Wozu das führt, merkst du ja gerade
Alpha_Wolf hat folgendes geschrieben: | | Ich bin grad etwas durchn Wind.. aber woher sollte dann Unit2 wissen was in Unit1 ist? Nur Unit1 weiss was in Unit2 ist.. |
Trag Unit1 im Uses Teil der Unit2 hinzu. Ggf. im Implementationsteil, um eine Überkreuzreferenzierung zu vermeiden. (also nach implementation noch eine uses Zeile einfügen)
Alpha_Wolf hat folgendes geschrieben: | | Ich weiss das doppelte Namensgebung nicht unbedingt gut ist.. |
Das ist schön formuliert 
_________________ We are, we were and will not be.
|
|
Alpha_Wolf 
      
Beiträge: 297
Ubuntu, Win XP, Win Vista
C#, Delphi 6 Prof, Delphi 2007 Prof, Java
|
Verfasst: Do 08.12.05 12:16
Danke für die Antworten
Hm.. also hab in Unit2 im uses Bereich die Unit1 reingeschrieben.
In Unit1 habe ich die Liste und den Record in public verschoben.
Wenn ich jetzt versuche irgendwo in Unit2 mit der Liste oder dem Record zu arbeiten (auch mit assign) bekomm ich ne AccessViolation. Wie umgeh ich das?
_________________ Diskutiere nie mit einem Irren - er zieht dich auf sein Niveau und schlägt dich mit seiner Erfahrung.
|
|
petergensfeld
      
Beiträge: 46
Windows Vista 32-Bit
Delphi XE Professional
|
Verfasst: Do 08.12.05 12:35
Um die Liste und den Record aus dem Public-Bereich der Klasse1 benutzen zu können, musst Du eine Instanz (=ein Objekt, per Create erzeugt) dieser Klasse zur Verfügung haben. Sonst bekommst Du eine Zugriffsverletzung.
Erkläre doch mal grob, was Du mit der Liste machen willst, vielleicht kann man Dir dann genauere Tipps geben. Vermutlich wird die Übergabe als Referenz die bessere Lösung sein, nur darfst Du diese nicht dauerhaft in Klasse2 speichern.
Gruß Dirk
|
|
opfer.der.genauigkeit
      
Beiträge: 754
Erhaltene Danke: 1
|
Verfasst: Do 08.12.05 12:42
Hi,
ein kleines Beispiel für den Umgang mit einem Record und einem Zeiger auf einen Record:
Unit1
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: 37:
| unit Unit1;
interface
uses Unit2, Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls;
type TForm1 = class(TForm) btnCopyRecord: TButton; procedure btnCopyRecordClick(Sender: TObject); private fMyRec: TMyRec; end;
var Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.btnCopyRecordClick(Sender: TObject); var lMyClass: TMyClass; begin lMyClass := TMyClass.Create; fMyRec.Test := 'TEST'; lMyClass.SetData( fMyRec ); lMyClass.SetData( @fMyRec ); FreeAndNil( lMyClass ); end;
end. |
Unit2
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:
| unit Unit2;
interface
type PMyRec = ^TMyRec; TMyRec = record Test: string; end;
TMyClass = class public procedure SetData(aMyRec: TMyRec); overload; procedure SetData(aMyRec: PMyRec); overload; end;
implementation
uses Dialogs;
procedure TMyClass.SetData(aMyRec: TMyRec); begin MessageDlg( aMyRec.Test, mtInformation, [mbOK], 0 ); end;
procedure TMyClass.SetData(aMyRec: PMyRec); begin MessageDlg( aMyRec.Test, mtInformation, [mbOK], 0 ); end;
end. |
Der Rest sollte sich erschließen lassen könen.
_________________ Stellen Sie sich bitte Zirkusmusik vor.
|
|
Alpha_Wolf 
      
Beiträge: 297
Ubuntu, Win XP, Win Vista
C#, Delphi 6 Prof, Delphi 2007 Prof, Java
|
Verfasst: Do 08.12.05 12:50
Kurze Erklärung:
Unit1 ist ein Modaler Dialog, Unit2 ist jediglich eine Klasse.
Ich habe eine Liste und einen Record in Unit1.
Diese fülle ich mit Daten aus einer TreeList.
Der Record besitzt 2 Felder mit Namen Value0 und Value1.
Ist das TreeListItem ein Parent kommt es in Value0,
ist es ein Child kommt es in Value1.
Die Liste und den Record schicke ich dann an eine extra Unit
die den Export zu Ecxel ermöglicht.
Mit der Liste bestimme ich die Anzahl der Zeilen für den Export.
In einer Schleife benutze ich nun 2 If-Anweisungen bei denen ich
jeweils prüfe ob Value0 leer ist (dann ist es ein Child) oder
ob Value1 leer ist (dann ist es ein Parent) je nachdem werden
die Inhalte die nicht leer sind in die erste Spalte(Parent)
oder in die zweite Spalte(Child) nach Excel exportiert.
Danke für die Hilfe!
_________________ Diskutiere nie mit einem Irren - er zieht dich auf sein Niveau und schlägt dich mit seiner Erfahrung.
|
|
petergensfeld
      
Beiträge: 46
Windows Vista 32-Bit
Delphi XE Professional
|
Verfasst: Do 08.12.05 12:55
@ opfer.der.genauigkeit
Fehlt da nicht ein "^"?
Delphi-Quelltext 1: 2: 3: 4:
| procedure TMyClass.SetData(aMyRec: PMyRec); begin MessageDlg( aMyRec^.Test, mtInformation, [mbOK], 0 ); end; |
|
|
opfer.der.genauigkeit
      
Beiträge: 754
Erhaltene Danke: 1
|
Verfasst: Do 08.12.05 13:06
Hallo petergensfeld,
die Dereferenzierung mit ^ ist nicht nötig.
Wenn ich mich recht entsinne entfällt dies seit der Version 4 von Delphi und dient nur der Abwärtskompatibilität.
Ich hab das in diesem Fall außer Acht gelassen, sollte der Korrektheit aber benutzt werden.
_________________ Stellen Sie sich bitte Zirkusmusik vor.
|
|
petergensfeld
      
Beiträge: 46
Windows Vista 32-Bit
Delphi XE Professional
|
Verfasst: Do 08.12.05 13:20
Hallo Alpha_Wolf,
zunächst zu Deinem Record, folgenden Aufbau fände ich irgendwie konsequenter:
Delphi-Quelltext 1: 2: 3: 4: 5:
| type TTreeListRecord = record Value: String; IsChild: Boolean; end; |
Du bräuchtest nur IsChild abzufragen und müsstest nicht immer ein leeres Feld mit Dir rumschleppen.
Warum führst Du in der Dialog-Klasse überhaupt eine zweite Liste mit den Einträgen (die hast Du ja dort schon in Deinem TreeView)? Oder brauchst Du die noch anderweitig? Wenn nicht, dann würde ich der SetData-Routine der Klasse TChecklistePrintProcessMgr eine Referenz auf das TreeView mitgeben und die Liste dort füllen und verwalten.
So in der Art könnte ich mir das vorstellen:
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16:
| procedure TChecklistePrintProcessMgr.SetData(tv: TTreeView); var i: Integer; ptlr: ^TTreeListRecord; begin for i:=0 to tv.Items.Count-1 do begin new(ptlr); ptlr^.Value:=tv.Items[i].Text; ptlr^.IsChild:=tv.Items[i].Parent<>nil; fTreeList.Items.Add(ptlr); end; end; |
@ opfer.der.genauigkeit
Da hab ich auch wieder was dazugelernt, muss ich in meinem D5 mal ausprobieren. Gut finde ich das aber nicht, sehr unsauber.
Gruß Dirk
|
|
opfer.der.genauigkeit
      
Beiträge: 754
Erhaltene Danke: 1
|
Verfasst: Do 08.12.05 13:28
petergensfeld hat folgendes geschrieben: |
@ opfer.der.genauigkeit
Da hab ich auch wieder was dazugelernt, muss ich in meinem D5 mal ausprobieren. Gut finde ich das aber nicht, sehr unsauber.
|
Wenn dich sowas beunruhigt, dann solltest du auch solche Sprachen wie C# meiden.
In den meisten fällen sieht man eh nicht, was alles referenziert bzw. dereferenziert wird, oder wo sich ein Zeiger versteckt und wo nicht.
Ich denke dabei an Dinge wie implizite Zeiger und Instanzen.
Ein Beispiel unter C++ ist z.B.:
rec->test;
Es handelt sich dabei auch um einen verstecken Typecast.
Und da wir grade bei sauberer Programmierung sind.
Variablenbezeichnungen alá 'i: integer' sind auch nicht immer vorteilhaft.
@Alpha_Wolf:
Wenn du eh jedem Knoten einen Record zuweist und dann jeweils prüfen möchtest ob es sich um ein Child oder Parent handelt, warum hängst du dann nicht entsprechend dem Knoten den Record als Data (Zeiger auf den Record) an, das geht bei den meisten Trees.
Wenn nicht, merk dir im Record den Knoten (Zeiger auf den Knoten) und benutze die Treefunktionen um festzustellen ob es ein Kind oder Parent ist.
Dadurch wärst du flexibler für Erweiterungen.
_________________ Stellen Sie sich bitte Zirkusmusik vor.
|
|
Stefan.Buchholtz
      
Beiträge: 612
WIN 2000, WIN XP, Mac OS X
D7 Enterprise, XCode, Eclipse, Ruby On Rails
|
Verfasst: Do 08.12.05 13:47
opfer.der.genauigkeit hat folgendes geschrieben: |
Wenn dich sowas beunruhigt, dann solltest du auch solche Sprachen wie C# meiden.
In den meisten fällen sieht man eh nicht, was alles referenziert bzw. dereferenziert wird, oder wo sich ein Zeiger versteckt und wo nicht.
Ich denke dabei an Dinge wie implizite Zeiger und Instanzen.
Ein Beispiel unter C++ ist z.B.:
rec->test;
Es handelt sich dabei auch um einen verstecken Typecast.
|
Wo ist denn da der Cast? Wenn rec ein struct oder ein Objekt ist, ist, heisst es rec.test, wenn rec ein Zeiger auf ein struct oder Objekt ist, heisst es rec->test - da läuft nix implizit ab.
opfer.der.genauigkeit hat folgendes geschrieben: | Und da wir grade bei sauberer Programmierung sind.
Variablenbezeichnungen alá 'i: integer' sind auch nicht immer vorteilhaft.
|
Na ja, man kann es auch übertreiben. i als Laufvariable in einer Schleife ist meiner Meinung nach völlig ok - man sollte es nur nicht für was anderes verwenden, dann wird es unübersichtlich.
Stefan
_________________ Ein Computer ohne Windows ist wie eine Schokoladentorte ohne Senf.
|
|
opfer.der.genauigkeit
      
Beiträge: 754
Erhaltene Danke: 1
|
Verfasst: Do 08.12.05 14:10
Stefan.Buchholtz hat folgendes geschrieben: | opfer.der.genauigkeit hat folgendes geschrieben: |
Ein Beispiel unter C++ ist z.B.:
rec->test;
Es handelt sich dabei auch um einen verstecken Typecast.
|
Wo ist denn da der Cast? Wenn rec ein struct oder ein Objekt ist, ist, heisst es rec.test, wenn rec ein Zeiger auf ein struct oder Objekt ist, heisst es rec->test - da läuft nix implizit ab.
|
Ich hab nix von Implizit im Bezug auf diesen Operator gesagt.
Das gilt z.B.: für dyn. Arrays.
Der Cast liegt aber hier versteck:
Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20:
| #include <iostream>
struct foo { char foo; };
int main() { foo *p; foo f; p = (foo *)malloc( sizeof(foo) ); p->foo = 'a'; std::cout << p->foo << std::endl; f = *p; std::cout << f.foo << std::endl; std::cout << ((foo)*p).foo << std::endl; std::cout << (*p).foo << std::endl; return 0; } |
-> ersetzt also die Dereferenzierung.
Das sind solche Dinge, die man schon garnicht mehr sieht.
Stefan.Buchholtz hat folgendes geschrieben: |
opfer.der.genauigkeit hat folgendes geschrieben: | Und da wir grade bei sauberer Programmierung sind.
Variablenbezeichnungen alá 'i: integer' sind auch nicht immer vorteilhaft.
|
Na ja, man kann es auch übertreiben. i als Laufvariable in einer Schleife ist meiner Meinung nach völlig ok - man sollte es nur nicht für was anderes verwenden, dann wird es unübersichtlich.
Stefan |
Nein, übertreiben sicherlich nicht. Aber man sollte es sich nicht für wichtige Variablen angewöhnen, sonst kommt man leicht durcheinander.
_________________ Stellen Sie sich bitte Zirkusmusik vor.
|
|
petergensfeld
      
Beiträge: 46
Windows Vista 32-Bit
Delphi XE Professional
|
Verfasst: Do 08.12.05 14:51
Hmm, da sehe ich genau wie Stefan aber dennoch einen Unterschied. f.foo und p->foo kann man durchaus noch unterscheiden. Bei dem Delphi-Beispiel benutzt Du aber exakt die gleiche Syntax, kannst also überhaupt nicht mehr erkennen, ob es sich um einen Pointer oder eine Strukturvariable handelt. Ich werde mir diese Syntax gar nicht erst angewöhnen (schon gar nicht, wenn man hier die korrekte Übergabe eines Records an eine Funktion aufzeigen will). Aber sie funktioniert in D5 tatsächlich, habe das eben mal ausprobiert.
Wichtige Variablen heißen bei mir auch nie i, für Laufvariablen nehme ich aber immer wieder gerne i,j,k... Ich glaube kaum, dass jemand Probleme haben wird, meine Quellcodes zu interpretieren (jedenfalls nicht deshalb  ).
Gruß, Dirk
|
|
opfer.der.genauigkeit
      
Beiträge: 754
Erhaltene Danke: 1
|
Verfasst: Do 08.12.05 15:16
Natürlich besteht da ein Unterschied.
Ich will auch nur darauf hinweisen, daß man nicht alles sieht was passiert.
Unter C# und sonstigen bequemen Sprachen sieht man eben noch weniger.
Für einen sauberen Stil sollte man das ^ sicherlich auch verwenden.
Im Zeitalter der Augen und Quelltexthinweise etc. laßen sich aber solche Dinge mit nur einem kurzen Blick klären.
Nebenbei erwähnt tut es mir aufrichtig leid, daß ich das in dem Beispiel nicht berücksichtigt habe. 
_________________ Stellen Sie sich bitte Zirkusmusik vor.
|
|
petergensfeld
      
Beiträge: 46
Windows Vista 32-Bit
Delphi XE Professional
|
Verfasst: Do 08.12.05 15:30
| Zitat: | | Unter C# und sonstigen bequemen Sprachen sieht man eben noch weniger. |
Ich weiß, in VB braucht man nicht mal Variablen zu definieren (ohne die Krücke mit "option explicit"). Grund genug für mich, Sprachen wie VB zu meiden, wo immer es geht. Ich hoffe nur, dass die Delphi-Language nicht auch in diese Richtung abgleitet.
|
|