Autor Beitrag
UweK
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 25

Win 7
Delphi Enterprise XE6
BeitragVerfasst: Do 04.02.21 17:31 
Hallo,

Ich suche einen Tipp, woran der folgende merkwürdige Effekt in Delphi XE6 liegen kann:

Ich habe eine Klasse von TFrame abgeleitet:
ausblenden Delphi-Quelltext
1:
2:
TMyFrameBasic = class(TFrame)
...


Diese Klasse enthält nur Variable und Prozeduren in "private" bzw. "public", die sie ihren Nachkommen zur Verfügung stellen soll. Ein eigene visuelle Komponente auf dem Bildschirm soll sie noch nicht erzeugen. Der Effekt ist unabhängig davon, ob ich dieser Klasse de guten Ordnung halber eine visuelle Komponente in Torm eines leeren TFrame in MyFrameBasic.dfm (und das zugehörige {$R *.dfm} im Quelltext) hinzufüge, oder ob ich beides weglasse und nur den Quelltext MyFrameBasic.pas ins Programm lade.

Von dieser Klasse leite ich weitere Klassen ab:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
TMyFrameVersion1 = class(TMyFrameBasic)
...
TMyFrameVersion2 = class(TMyFrameBasic)
...

die jeweils verschiedene visuelle Komponenten enthalten und nur die von TMyFrameBasic bereitgestelllten Variablen und Prozeduren nutzen.

Das funktioniert einwandfrei, solange ich die Delphi Entwicklungsumgebung geöffnet halte. Beende ich Delphi und starte es ein andermal wieder, erhalte ich beim Laden des Projekts die unsinnige Fehlermeldung "Fehler beim Lesen MyFrameVersion1.TabOrder: Eigenschaft TabOrder existiert nicht. Den Fehler ignorieren oder fortsetzen?" Das Gleiche dann auch nochmal für "MyFrameVersion2". Ignoriere ich diese Fehlermeldungen, verschwinden die Instanzen dieser Frames aus allen Formularen im Projekt.

Erst dachte ich, ich hätte mit das Projekt komplett zerschossen, aber folgendes rettete mich:
1. Außerhalb von delphi mit einem Texteditor die obigen Klasenableitungen umändern auf:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
TMyFrameVersion1 = class(TFrame)
...
TMyFrameVersion2 = class(TFrame)
...


2. Delphi starten => Jetzt kann das Projekt gelesen werden, und es gibt lediglich viele Fehlermeldungen weil die in "MyFrameBasic" enthaltdenen Definitionen natürlich nicht mehr sichtbar sind.

3. Jetzt in der laufenden Delphi-Entwicklungsumgebung die beiden Klassennamen wieder zurück ändern:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
TMyFrameVersion1 = class(TMyFrameBasic)
...
TMyFrameVersion2 = class(TMyFrameBasic)
...


Und alles funktioniert wieder. ich kann das Programm weiterentwickeln - aber nur bis zum nächsten Feierabend an dem im die Entwicklungsumgebung schließe. Dann geht dasselbe wieder von vorn los.

Hat jemand eine Idee, woran das liegen könnte? Vielen Dank im Voraus!


Moderiert von user profile iconTh69: Topic aus Delphi Language (Object-Pascal) / CLX verschoben am Do 04.02.2021 um 18:08
Moderiert von user profile iconNarses: Topic aus Sonstiges (Delphi) verschoben am Do 04.02.2021 um 23:22
Gausi
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 8488
Erhaltene Danke: 451

Windows 7, Windows 10
D7 PE, Delphi XE3 Prof, Delphi 10.3 CE
BeitragVerfasst: Do 04.02.21 20:15 
Bei solchen Konstrukten muss iirc die Basis-Unit geöffnet bleiben. D.h. die Datei MyFrameBasic.pas (bzw. dfm) muss in der IDE auch geöffnet sein.

Probier also mal so:
  • MyFrameBasic.pas /.dfm laden
  • Davon abgeleitete Units öffnen
Solange du die MyFrameBasic nicht schließt, sollte das auch beim nächsten Start der IDE ohne Fehler durchlaufen.

Ansonsten: auf "Abbrechen" statt "Ignorieren" klicken. Dann wird nichts gelöscht, man kann allerdings ggf. nicht in die Form-Ansicht wechseln, sondern kann nur den Quellcode (also die *.pas) bearbeiten.

_________________
We are, we were and will not be.
UweK Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 25

Win 7
Delphi Enterprise XE6
BeitragVerfasst: Mi 10.02.21 16:04 
Hallo Gausi,

Das ist leider nicht die Ursache. Die Basisunit MyFrameBasic.pas/.dfm wird stets mit dem Projekt in der IDE geöffnet.

Ich habe auch versucht, bei Öffnen des Projekts nur die Basisunit zu öffnen (indem ich vor Beenden der IDE die beiden abgeleiteten Units schloss), um dann diese beiden davon abgeleiteten Units MyFrameVersion1 und MyFrameVersion2 erst nach komplettem erneuten Start der IDE von Hand zu öffnen. Das brachte aber auch nichts, denn die diversen anderen Formulare, in die diese beiden abgeleiteten Units eingefügt sind, melden dann trotzdem den Fehler "TMyFrameVersion1 nicht gefunden", und ihre Formulare werden ebenfallls nicht geöffnet. Diese Fehlermeldung ist immer gleich, egal ob die abgeleiteten Units beim Öffnen der IDE gleich mit geöffnet werden oder nicht.

Das einzige was im Moment hilft ist Auskommentieren der Klassenableitungen, so wie ich es schon in meiner Anfrage beschrieb:

- In einem Editor zunächst die Klassenableitung durch Kommentarzeichen verstecken:
ausblenden Delphi-Quelltext
1:
2:
//TMyFrameVersion1 = class(TMyFrameBasic)
TMyFrameVersion1 = class(TFrame)


- dann die IDE starten => funktioniert

- dann in der IDE die Kommentarzeichen vertauschen:
ausblenden Delphi-Quelltext
1:
2:
TMyFrameVersion1 = class(TMyFrameBasic)
//TMyFrameVersion1 = class(TFrame)


Nun läuft das Programm einwandfrei. Es kann also keine unzulässige Klassenableitung sein, sondern nur irgend etwas, was direkt im Startvorgang der IDE hängen bleibt.

Das ständige Ändern ist zwar unbequem, aber geht zumindest als Notnagel um überhaupt weiterzukommen.

Hat noch jemand eine weitere Idee, was ich mal probieren könnte? Eventuell über bedingte Compilierung mit {$IFDEF} & Co., wenn es irgendwas gäbe um festzustellen, in welchem Zustand sich die IDE gerade befindet?


Am Ende müsste es ja auch nicht unbedingt eine Ableitung auf dem Weg über eine "Zwischenklasse" TMyFrameBasic sein, wenn das aus mysteriösen Gründen gar nicht geht. TMyFrameBasic hat selbst gar keine visuellen Komponenten und stellt nur gemeinsame Variable und Prozeduren für TMyFrameVersion1 und TMyFrameVersion2 zur Verfügung. Theoretisch könnte ich auch eine normale Unit "TGemeinsames" mit lauter globalen Prozeduren schreiben, die dann die entsprechenden visuellen Komponenten aus TTMyFrameVersion1=class(TFrame) bzw. TMyFrameVersion2=class(TFrame) jeweils als Parameter übergeben bekommen. Aber das empfinde ich als keine "ordentliche" objektorientierte Programmierung. Und mindestens die Variablen müssten in TMyFarmeVersion1 und TMyFrameVersion 2 privat doppelt stehen, da sie nicht mehr auf dem Vererbungswege für jede der abgeleiteten Klassen privat instanziiert würden. Ein Mischen von Klassen im Stile von MyFrameVersion1 = class(TFrame, TGemeinsam) wie bei C++ ist ja bei Delphi leider nicht möglich.
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 18978
Erhaltene Danke: 1679

W10 x64 (Chrome, Edge)
Delphi 10.4 Ent, Oxygene, C# (VS 2019), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Do 11.02.21 20:18 
Ich habe folgendes mit XE6 Enterprise (wie im Profil angegeben) und 10.2 getestet:
- Neue VCL-Anwendung
- Datei --> Neu --> Weitere --> Delphi-Dateien --> VCL-Frame
- Datei --> Neu --> Weitere --> Vererbbare Elemente --> Den eben erstellten Frame ausgewählt
- Auf dem Formular in der Tool-Palette Frames ausgewählt und den vererbten Frame ausgewählt (bei dem als Typ auch "TFrame(Inherited)" steht)
- Delphi geschlossen und wieder gestartet
- Projekt wieder geöffnet

Ich kann das Problem nicht nachvollziehen. Ich kann die Frames normal öffnen, ändern, alles...

Für diesen Beitrag haben gedankt: UweK
UweK Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 25

Win 7
Delphi Enterprise XE6
BeitragVerfasst: Fr 12.02.21 17:08 
Hallo jaenicke,

Vielen Dank, das war der entscheidende Hinweis. Ich hatte die abgeleitete Klasse TMyFrameVersion1 dem Projekt direkt von Hand an allen erforderlichen Stellen hinzugefügt, weil das so schön bequem war: einfach die ursprünglich nur eine Datei mit TMyFrame auf die beiden Dateinamen mit TMyFrameBasic (für allgemein verwendbares) und TMyFrameVersion1 (für Spezielles der Version 1) kopiert und das jeweils nicht hineingehörende gelöscht. So etwas hat auch stets funktioniert, aber offensichtlich nur so lange keine Formulardatei *.dfm beteiligt ist. Deinen angegebenen Weg habe ich mal mit 2 Testframes probiert und deren *.dfm-Dateien verglichen:

Für TFrame1 = class(TFrame) steht in *.dfm als erste Zeile:
ausblenden Delphi-Quelltext
1:
2:
object Frame1: TFrame1
...


Für TFrame2 = class(TFrame1) steht in *.dfm als erste Zeile:
ausblenden Delphi-Quelltext
1:
2:
inherited Frame2: TFrame2
...


Die abgeleitete Klasse braucht dort einfach nur ein anderes erstes Schlüsselwort "inherited" anstelle "object" der Basisklasse. Ensprechend habe ich das in meinen Formulardateien geändert, und alles funktioniert. Das falsche Schlüsselwort hat nur beim Öffnen des Projekts gestört, aber eigenartigerweise nicht beim Compilieren und zur Laufzeit.