Autor Beitrag
chrissi1968
Hält's aus hier
Beiträge: 7

Win XP
Delphi 2007 Prof.
BeitragVerfasst: Do 04.11.10 19:33 
Hallo,

ich habe folgendes Problem:
In einer MDI-Anwendung erzeuge ich ein MDIChild. Nun möchte ich aus dem MDIParent (Oder einem anderen MDIChild) eine procedure innerhalb dieses Childs aufrufen. Das klappt auch, nur erhalte ich eine Zugriffsverletzung wenn ich innerhalb dieser procedure eine Komponente aufrufe welche sich auf dem Child-Formular befindet.

Hat jemand von Euch eine Idee woran dies liegen könnte bzw. wo man sowas nachlesen kann?

Vielen Dank und viele Grüße

Chrissi
bummi
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 1248
Erhaltene Danke: 187

XP - Server 2008R2
D2 - Delphi XE
BeitragVerfasst: Do 04.11.10 19:38 
wird schwierig ohne Code...
chrissi1968 Threadstarter
Hält's aus hier
Beiträge: 7

Win XP
Delphi 2007 Prof.
BeitragVerfasst: Do 04.11.10 22:33 
Hallo,

hier der Code:

1) Erzeugung der Child-Formulare:

ausblenden 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:
procedure TFMain.CreateMDIChild(frm: TFormClass);
var
  i       : Integer;
  bCreated: Boolean;
  fForm   : TForm;

begin
  { ein neues untergeordnetes MDI-Fenster erstellen }
  bCreated:=False;
  for i := 0 to FMain.MDIChildCount - 1 do
  begin
    if FMain.MDIChildren[i] is frm then
    begin
      fForm:=FMain.MDIChildren[i] as frm;
      bCreated:=True;
      Break;
    end;
  end;
  if not bCreated then
    frm.Create(Application)
  else
  begin
    FForm.ActiveMDIChild;
    FForm.Show;
  end;
end;

Hier der Aufruf:
....
CreateMDIChild(TFVPlan);
....

2) Die function innerhalb des Child:

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
procedure TFVPlan.ScrollToNodeInCalendar(iMachine: Integer; iOrder: Integer);
var
  dtBeginn: TDateTime;
  iNode   : IVcNode;

begin
  // Die nachfolgende Codezeile führt zum Fehler:
  iNode:=VcPlan.GetNodeByID(IntToStr(iMachine) + '|' + IntToStr(iOrder));
  if iNode <> nil then
  begin
    dtBeginn:=iNode.DataField[4];
    VcPlan.ScrollToNode(iNode, vcLeftAligned);
    VcPlan.ScrollToDate(dtBeginn, vcLeftAligned, 2);
    iNode.MarkNode:=True;
  end;
end;

3) Und hier der Aufruf aus einem anderen Child:

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
procedure TFVPlanningData.TBSelectionFindClick(Sender: TObject);
var
  iMachine: Integer;
  iOrder  : Integer;
  i: Integer;
begin
  iMachine:=DSSQLPlanDB.DataSet.FieldByName('P_Maschine').AsInteger;
  iOrder:=DSSQLPlanDB.DataSet.FieldByName('B_Auftrag').AsInteger;
  for i := 0 to FMain.MDIChildCount - 1 do
  if FMain.MDIChildren[i] is TForm then
  begin
    if TForm(FMain.MDIChildren[i]).Name = 'FVPlan' then
    begin
      FMain.MDIChildren[i].BringToFront;
      FMain.MDIChildren[i].SetFocus;
      FVPlan.ScrollToNodeInCalendar(iMachine, iOrder);
      break;
    end;
  end;
end;

Dies ist meine erste MDI-Applikation, habe also von MDI keine Ahnung! In der Applikation werden Aufträge graphisch dargestellt und es wäre schön wenn man von dem Datengrid (Child1) durch anklicken eines Auftrages diesen im graphischen Grid (Child2) sehen könnte.

Krachen tut's hier:
ausblenden Delphi-Quelltext
1:
2:
3:
  // Die nachfolgende Codezeile führt zum Fehler:
    iNode:=VcPlan.GetNodeByID(IntToStr(iMachine) + '|' + IntToStr(iOrder));
  // Dabei ist dieses iNode sozusagen eine Komponente von Child2.

Wird die function innerhalb vom Formular selbst aufgerufen funzt's einwandfrei!

Ich habe auch mal versucht dies mit zwei einfachen Formularen und zwei Buttons darzustellen. Auch hier das gleiche Problem!

Vielen Dank und viele Grüße

Chrissi
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19346
Erhaltene Danke: 1754

W11 x64 (Chrome, Edge)
Delphi 12 Pro, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Do 04.11.10 22:55 
Vermutlich ist VcPlan nicht initialisiert. Das siehst du aber ja im Debugger.

Bei welcher Adresse passiert denn die Schutzverletzung? Wenn das Adresse z.B. 20 oder sowas in der Größenordnung ist, dann ist das Objekt nicht initialisiert.
bummi
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 1248
Erhaltene Danke: 187

XP - Server 2008R2
D2 - Delphi XE
BeitragVerfasst: Do 04.11.10 23:49 
ich vermute die böse Ecke ist
FVPlan.ScrollToNodeInCalendar(iMachine, iOrder);

wenn ich es richtig verstanden werden die MDI's ohne Zuweisung erzeugt es wäre die Frage was in FVPlan steht.

ausblenden Delphi-Quelltext
1:
2:
  if not bCreated then
    frm.Create(Application
chrissi1968 Threadstarter
Hält's aus hier
Beiträge: 7

Win XP
Delphi 2007 Prof.
BeitragVerfasst: Fr 05.11.10 11:29 
Hallo,

zunächst schon mal herzlichen Dank für Eure Hilfe!

Ich habe auch mal versucht diesen Fehler an einem einfachen Beispiel zu simulieren:
In einer MDI-Anwendung gibt es zwei Formulare:
- Eines welches als "fsNormal" und
- eines welches als "fsMDIChild" erzeugt wird

Auf beiden Formularen gibt es einen Button. Nach der Erzeugung der Formulare frage ich aus dem "fsMDIForm" den caption des Buttons durch eine procedure innerhalb des Formulars ab:

1) Erzeugung von fsMDIChild:
ausblenden 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:
procedure TFMainForm.CreateMDIChild(frm: TFormClass);
var
  i       : Integer;
  bCreated: Boolean;
  fForm   : TForm;
  Child: TFTest1;

begin
  { ein neues untergeordnetes MDI-Fenster erstellen }
  bCreated:=False;
  for i := 0 to FMainForm.MDIChildCount - 1 do
  begin
    if FMainForm.MDIChildren[i] is frm then
    begin
      fForm:=FMainForm.MDIChildren[i] as frm;
      bCreated:=True;
      Break;
    end;
  end;
  if not bCreated then
  begin
    frm.Create(Application)
  end
  else
  begin
    FForm.ActiveMDIChild;
    FForm.Show;
  end;
end;


2) Erzeugung von fsNormal:

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
procedure TFMainForm.Formular21Click(Sender: TObject);
begin
  Application.CreateForm(TFTest2, FTest2);
  FTest2.Show;
end;


3) Abfrage im MDIChild:

ausblenden Delphi-Quelltext
1:
2:
3:
4:
procedure TFTest1.KomponenteTest1;
begin
  ShowMessage(Button1.Caption);
end;


--> Zugriffsverletzung bei Adresse 004728D1 in Modul "MDIAPP.exe". Lesen von Adresse 00000360.

4) Abfrage im "Normalen" Fenster:

--> Funzt!

Die Zugriffsverletzung in meinem eigentlichen Projekt lautet:

Zugriffsverletzung bei Adresse 008534A2 in Modul "MDIAPP.exe". Lesen von Adresse 00000394.

Dieses VcPlan ist eine ActiveX-Komponente. Ich habe versucht an dieser Stelle nur mal die caption eines Buttons abzufragen:

.....
ShowMessage(TBExit.Caption);
--> Kracht genau so!!!!
iNode:=VcPlan.GetNodeByID(IntToStr(iMachine) + '|' + IntToStr(iOrder));
.....

Zugriffsverletzung bei Adresse 00853465 in Modul "CkPlan.exe". Lesen von Adresse 0000036C.

Es scheint mir so als ob ich auf die einzelnen Objekte meines Child-Formulars keinen Zugriff haben wenn ich dieser Zugriff von außen kommt. Bei einem "normalen" Formular klappt das einwandfrei!

Viele Grüße

Chrissi
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19346
Erhaltene Danke: 1754

W11 x64 (Chrome, Edge)
Delphi 12 Pro, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Fr 05.11.10 11:48 
user profile iconchrissi1968 hat folgendes geschrieben Zum zitierten Posting springen:
ausblenden Delphi-Quelltext
1:
    frm.Create(Application)					
Aua...
Du rufst die Methode Create des nicht existierenden Objekts frm auf...
Wie war das nochmal mit einem Konstruktoraufruf? ;-)

Für diesen Beitrag haben gedankt: chrissi1968
chrissi1968 Threadstarter
Hält's aus hier
Beiträge: 7

Win XP
Delphi 2007 Prof.
BeitragVerfasst: Fr 05.11.10 12:10 
Ups....... :autsch: :autsch: :autsch: :autsch: :autsch: :autsch:

Vielen herzlichen Dank!
Das kommt davon wenn man aus Planlosigkeit einen Code abtippt!

Funzt jetzt supergut und einwandfrei!!

Viele Grüße

Chrissi
SvenAbeln
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 334
Erhaltene Danke: 3



BeitragVerfasst: Fr 05.11.10 12:16 
user profile iconjaenicke hat folgendes geschrieben Zum zitierten Posting springen:
user profile iconchrissi1968 hat folgendes geschrieben Zum zitierten Posting springen:
ausblenden Delphi-Quelltext
1:
    frm.Create(Application)					
Aua...
Du rufst die Methode Create des nicht existierenden Objekts frm auf...
Wie war das nochmal mit einem Konstruktoraufruf? ;-)


frm ist hier aber doch kein Objekt sondern eine Klasse:
ausblenden Delphi-Quelltext
1:
procedure TFMainForm.CreateMDIChild(frm: TFormClass);					
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19346
Erhaltene Danke: 1754

W11 x64 (Chrome, Edge)
Delphi 12 Pro, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Fr 05.11.10 12:22 
Stimmt, da habe ich wiederum nicht drauf geachtet. Der Name ist dann ja auch sehr passend gewählt... :roll:

Die Stelle ist aber trotzdem die richtige. Denn das Ergebnis wurde weggeworfen, ich vermute mal das hat er jetzt auch korrigiert in:
ausblenden Delphi-Quelltext
1:
fForm := frm.Create(Application);					
chrissi1968 Threadstarter
Hält's aus hier
Beiträge: 7

Win XP
Delphi 2007 Prof.
BeitragVerfasst: Fr 05.11.10 13:19 
Kleiner Nachtrag:

Habe die function für das Erzeugen der Childs wie folgt geändert:

ausblenden 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:
procedure TFMain.CreateMDIChild(frmClass: TFormClass; var refObj);
var
  i       : Integer;
  bCreated: Boolean;
  fForm   : TForm;

begin
  { ein neues untergeordnetes MDI-Fenster erstellen }
  bCreated:=False;
  for i := 0 to FMain.MDIChildCount - 1 do
  begin
    if FMain.MDIChildren[i] is frmClass then
    begin
      fForm:=FMain.MDIChildren[i] as frmClass;
      bCreated:=True;
      Break;
    end;
  end;
  if not bCreated then
  begin
//      frmClass.Create(Application)
    Application.CreateForm(frmClass, refObj);
  end
  else
  begin
    TForm(fForm).ActiveMDIChild;
    TForm(fForm).Show;
  end;
end;


Der Aufruf erfolgt dann:

CreateMDIChild(TFVPlan, FVPlan);

Vielen Dank nochmal und viele Grüße

Chrissi
bummi
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 1248
Erhaltene Danke: 187

XP - Server 2008R2
D2 - Delphi XE
BeitragVerfasst: Fr 05.11.10 13:27 
wäre es wie unten stehen nicht intuitiver und universeller einsetzbar, falls Du doch mal 2 Forms der Selben Klassse benötigst?

ausblenden 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:
procedure TForm1.CreateMDIChild(frmClass: TFormClass; var refObj);
var
  i       : Integer;
  bCreated: Boolean;
begin
  bCreated:=False;
  for i := 0 to MDIChildCount - 1 do
  begin
    if MDIChildren[i]=Tform(refObj) then
    begin
      bCreated:=True;
      Break;
    end;
  end;
  if not bCreated then
  begin
    Application.CreateForm(frmClass, refObj);
  end
  else
  begin
    TForm(refObj).ActiveMDIChild;
    TForm(refObj).Show;
  end;
end;
chrissi1968 Threadstarter
Hält's aus hier
Beiträge: 7

Win XP
Delphi 2007 Prof.
BeitragVerfasst: Fr 05.11.10 15:00 
Hallo brummi,

ja, Deine Lösung ist besser!! :lol: :lol:

Viele Grüße

Chrissi