Basisklasse definieren, ich kriegs ned hin

Hallo,

ich muss als Studienprojekt eine Notenverwaltung in Delphi programmieren.
Ich habe eine MDI-Anwendung, und es gibt 4 verschiedene MDI-Child-Windows die darin vorkommen können.
Diese haben jedoch alle Ähnlichkeiten, nämlich z.B. hat jedes eine TDBGrid Komponente namens DBGrid1.

Ich krieg es jetzt aber ned hin von extern auf dieses grid zuzugreifen.
Bisher habe ich das immer etwas kompliziert gelöst:

var window: TForm

window := Form\_Main.ActiveMDIChild;
if (window is TForm\_soundso) then
begin
 (window as TForm\_soundso).DBGrid1.....
end;

Und das für jeden Fenstertyp einmal, das gefällt mir aber ganz und gar nicht (wenn es auch funktioniert.

Nun dachte ich mir ich bau mir eine Basisklasse für all diese MDI-Children.
Ich habe diese Klasse folgendermassen definiert

type
 TMDIChild = class(TForm)
 private
 public
 DBGrid1: TDBGrid;
end;

Nun leite ich meine Child-Windows nicht mehr von TForm direkt ab, sondern von eben dieser TMDIChild.

Allerdings wenn ich nun folgendes probiere:

var window: TMDIChild

window := (Form\_Main.ActiveMDIChild as TMDIChild);
window.DBGrid1....

dann erhalte ich eine Access Violation. Wieso? Das muss doch irgendwie gehen, dass ich ned jedesmal ein if brauche sondern für alle MDIChilds den gleichen Aufruf verwenden kann.
Muss ich die Basisklasse vielleicht irgendwie als abstrakt definieren? Wenn ja wie geht das oder was hilft sonst.

Tausend Dank für Anregungen, habe vorher leider noch nie mit Delphi programmiert und entsprechend viel Ahnung, aber es wird langsam.

MfG Bruno

Hi,

das Problem der „Allgemeinen Schmutzverletzung“ dürfte daran liegen, daß es nicht genügt einer Variablen (hier: window) einfach einen Typen zuzuweisen (window := Form_Main.ActiveMDIChild as TMDIChild)). Es muß grundsätzlich eine Instanz Speicherabbild) mit der entsprechenden Typinformation gebildet werden. Im Regelfall erfolgt dies durch eine Anweisung der Form „Window := TMDIChild.Create(Application)“.

Das Grundgerüst hierfür erstellt Delphi automatisch, durch „Datei\Neu\Projekte\MDI-Anwendung“. Dem ChildWindow kann dann durch einfaches Drag-And-Drop die DBGrid-Komponente hinzugefügt werden (Deklaration erfolgt automatisch).

Hier ein Beispiel wie ohne direktes Ansprechen der einzelnen ChildWindows auf jede Instanz von ChildWindow.DGrid zugegriffen werden kann. Als Beispiel wird der Hintergrund jeder Instanz von ChildWindow.DBGrid auf Tastendruck rot eingefärbt.

{*************************************************************}
procedure TMainForm.Button1Click(Sender: TObject);
var
i: integer; {Verschachtelungstiefe = 1}
begin
with application do
for i:=0 to Application.ComponentCount-1 do {Alle Komponenten werden durchlaufen}
begin {hier Typprüfung, wenn erfolgreich, dann rot einfärben}
If (Components[i]is TMDIChild) Then (Components[i]as TMDIChild).DBGrid1.Color:=clRed ;
end;
end;
{**************************************************************}

Gruß
U.Teichert

[Bei dieser Antwort wurde das Vollzitat nachträglich automatisiert entfernt]

Mir scheint eher das Problem ist, dass er wenn ich das aktuelle MDI Window nach TMDIChild caste, dann auf das DBGrid1 von TMDIChild zugreifen will, obwohl dieses gar nicht instanziiert wurde, sondern nur von der tieferen Klasse… hmm verstehst du was ich meine?
Wie muss ich denn meine TMDIChild und die daraus abgeleiteten Klassen definieren damit ich beim Zugriff auf TMDIChild.DBGrid1 automatisch im abgeleiteten Grid lande… kann mir da jemand schnell ne Klassendefinition geben? so wie ich das gemacht habe funktioniert es nicht. In C++ kann ich eine abstrakte Basisklasse definiere, damit das Programm zur Laufzeit die richtige Unterklasse auswählt, weiss aber ned ob und wie das in Delphi geht :smile:

MfG Bruno

Hi Bruno!

Mir scheint eher das Problem ist, dass er wenn ich das
aktuelle MDI Window nach TMDIChild caste, dann auf das DBGrid1
von TMDIChild zugreifen will, obwohl dieses gar nicht
instanziiert wurde, sondern nur von der tieferen Klasse… hmm
verstehst du was ich meine?

„Ich versteh Dich sehr gut“ (Zitat aus schätzungsweise 2538 Hollywood-Schnulzen :smile:). OK, nun zum ernsten Teil… Da Du das Problem schon richtig erkannt hast, spar ich mir weitere Erklärungen dazu und komme gleich zur Lösung.

Das, was Du brauchst, heißt „Formularvererbung“, und der Grund, warum Du das brauchst, ist folgender. Wenn Du auf „normalem“ Wege, d. h. über den Menüpunkt „File/New Form“ (my Delphi is a english one – please translate yourself into german), ein Formular zu Deinem Projekt hinzufügst, dann ist dieses vom Typ „TForm1“ oder „TForm2“ oder „TForm74“, und alle diese Klassen „TFormX“ sind IMMER von „TForm“ abgeleitet. Mit Deinem offensichtlich guten Verständnis der OOP ist Dir klar, daß Du damit schon „verloren“ hast, denn diese Klassenhierarchie ist nicht die, die Du gerne hättest. Jeder Versuch, da noch was „nachträglich“ dran zu drehen, ist auch von vornherein zum Mißerfolg verdammt (weil die Gründe prinzipieller Natur sind).

Um die gewünschte Klassenhierarchie

 TChildWinCommon(TForm)
 TChildWin1(TChildWinCommon) 
 TChildWin2(TChildWinCommon) 
 TChildWin3(TChildWinCommon) 
 TChildWin4(TChildWinCommon) 

zu erhalten (wobei dann „TChildWinCommon“ mit dem Grid bestückt ist), mußt Du so vorgehen.

  1. Zunächst erstellst Du ganz normal über „File/NewForm“ Dein Basisformular „TChildWinCommon“, wohinein Du ordentlich das Grid setzen tust und so weiter.

  2. Dann wählst Du den Menüpunkt „File/New“ (nicht „File/NewForm“!). In dem erscheinenden Dialog wechselst Du auf den Registertab „Project1“ (ich gehe einfach davon aus, daß Dein Projekt „Project1“ heißt). Dort erwartet Dich eine Liste mit sämtlichen Formularklassen, die in Deinem Projekt definiert sind. Wähle „TChildWinCommon“. Unten siehst Du, daß hier nur „Inherit“ zur Auswahl steht und das ist ja auch genau das, was Du willst („Copy“ und „Use“ ist deaktiviert, weil das hier keinen Sinn machen würde).

  3. Wähle „OK“. Damit hast Du jetzt Dein neues Formular, dessen Klasse von „TChildWinCommon“ abgeleitet ist (Du brauchst seinen Namen nur noch auf „ChildWin1“, „ChildWin2“ etc. zu setzen). Du siehst, daß es das Grid schon auf wundersame Weise enthält, wie es ja eigentlich auch zu erwarten ist. Wenn Dich das noch nicht überraschen sollte, dann verschieb mal das Grid mit der Maus im „TChildWinCommon“-Basisformular, oder füg dem Basisformular einen Button hinzu… Jede Änderung an dem Basisformular wird sofort automatisch in alle abgeleiteten Formulare übernommen (umgekehrt natülich nicht). Delphi leistet hier also richtig gute Arbeit (deshalb mag ich’s ja auch so :smile:.

So, um das weitere mußt Du Dich jetzt selbst kümmern :smile:. Ach ja, noch was: Mit „abstrakten Basisklassen“ hat das alles gar nichts zu tun, darum brauchst Du Dir hier also keine Gedanken zu machen.

Ich hoffe, ich konnte Dir helfen.

Mit freundlichem Gruß
Martin