Zugriffsverletzung bei Zugriff auf Komponenten eines MDI-Child
-
Also meinem Verständnis nach rufe ich lagerplatz_anlegen genau an der Stelle auf die ich oben schon reinkopiert habe. Das ganze steht im MainForm meines Programms.
Was genau sind denn Member-Variablen und wo geschweige denn wie erstelle ich die in meinem Fall?
-
Membervariablen, sind Variablen innerhalb deiner Form-Klasse. Schau doch mal in die Headerdatei, wo Thauptmenu deklariert wurde. Alle Variablen, die da unter private: public: etc. stehen sind Membervariablen bzw. Funktionen.
Deine Variable lagerplatz_anlegen ist lokal in Lagerplatzanlegen1Click und somit nach Verlassen dieser Funktion ungültig.
Schreibs mal soif (!gefunden) { //Fuhrpark erstellen lagerplatz_anlegen = new Tlagerplatz_anlegen(Application); lagerplatz_anlegen->Show(); }PS.
Es wäre gut, wenn du dir mal ein Grundlagentutorial zu C++ durchliest. Insbesondere alles über Gültigkeitsbereiche von Variablen und Klassen.
http://tutorial.schornboeck.net/scope.htm
http://tutorial.schornboeck.net/oop2.htm und nachfolgende Seiten
Am besten überhaupt alles.
-
@Braunstein
So funktioniert das jetzt.Was genau ist denn jetzt der Unterschied zwischen:
Tlagerplatz_anlegen *lagerplatz_anlegen = new Tlagerplatz_anlegen(Application);und
lagerplatz_anlegen = new Tlagerplatz_anlegen(Application);Im oberen wird lagerplatz_anlegen direkt in der Funktion deklariert. Wo wird es jetzt aber beim unteren deklariert?
Edit1:
Danke, werde mir die Links mal anschauen.
-
EPMS schrieb:
... Wo wird es jetzt aber beim unteren deklariert?
In der Headerdatei von Thauptmenu.
-
Hallo
das untere funktioniert nur wenn bereits eine solche Variable vorher deklariert wurde. Das kann in der selben Methode sein, das kann aber auch als Member der Form oder gar global sein.
Schau dir noch mal in einem C++Grundlagen-Tutorial Gültigskeitsbereiche/Scopes an.bis bald
akari
-
Werde mir das mal durchlesen.
Allerdings finde ich in der Headerdatei von Thauptmenu nichts bezüglich "lagerplatz_anlegen". Dort steht darüber nichts.
-
Hallo
du must doch wissen, wo du die Variable deklariert hast... Tip : benutz die IDE-Funktion zum Suchen von Text in den Projektdateien, um das zu finden.
bis bald
akari
-
Andere Variante
Halte Strg fest und klicke mit der linken Maustaste auf deine Variable in der Funktion, dann springt er zur Deklaration (dauert manchmal etwas).
-
Jetzt habe ich es gefunden. Sie werden in der Headerdatei des jeweiligen Forms deklariert.
Jetzt habe ich noch eine Frage:
- Wenn ich im OnCreate oder OnActivate folgendes eingebe:lagerplatz_anlegen->Label15->Caption = "test";Bekomme ich auch wieder eine Zugriffsverletzung. Das liegt doch dann bestimmt auch wieder daran, dass lagerplatz_anlegen noch nicht deklariert ist oder?
Edit1:
Wenn ich unter Projekt->Optionen das Formular auf "Automatisch erzeugen" stelle habe ich die Zugriffsverletzung nicht. D.h. wenn ich es nicht automatisch erzeugen lasse ist es noch nicht da und deshalb kommt die Fehlermeldung oder?Sorry wegen der vielen Fragen.
-
Die Variable ist schon deklariert. Das ist allerdings nur ein (in OnCreate ungültiger) Zeiger auf Tlagerplatz_anlegen. Erst durch aufrufen von new usw. erzeugst du eine gültige Instanz. Das gleiche geschieht automatisch wenn du das Formular in "Automatisch erzeugen" einträgst.
-
Durch meinen aufruf mit
lagerplatz_anlegen = new Tlagerplatz_anlegen(Application);erzeuge ich also eine neue gültige Instanz?
Wieso geht dann aber mein oben beschriebener Befehl nicht? Oder kann ich sowas in OnCreate oder OnActivate überhaupt nicht aufrufen?
Wenn ich es so
Label15->Caption = "test";aufrufe kommt keine Fehlermeldung. Damit wäre ich ja fast beim gleichen Fehler wie am Anfang. Das verstehe ich jetzt nicht wirklich.
*langsam am verzweifeln*
-
Lies dir einfach erstmal die Tutorials durch. Dann sollte dir das klar werden.
-
@Braunstein,
habe mir das jetzt mal angeschaut. Klingt mir alles auch sehr logisch und denke ich habe das verstanden.Leider weiß ich nicht, wo jetzt genau mein Fehler liegt. Weil nur "new" habe ich das Formular doch erzeugt. Wieso kann ich dann meinen Befehl im OnCreate oder OnActivate nicht ausführen?
-
Geh doch mal mit dem Debugger durch und setze dir Breakpoints bei deiner Erzeugung mit new sowie in OnCreate bzw. OnActivate und schau in welcher Reihenfolge diese Funktionen aufgerufen werden.
-
Gute morgen nochmals,
ich habe jetzt mal Breakpoints gesetzt. Demnach kommt erst das New, dann OnCreate und dann OnActivate. Dann gehts wieder zurück und es wird das nach New ausgeführt.
Aufrufen tue ich das Formular ja folgendermaßen:
artikel_anlegen = new Tartikel_anlegen(Application); artikel_anlegen->WindowState =wsMaximized; artikel_anlegen->Show();Das "Show" wird erst nach OnCreate und OnActivate ausgeführt. Kann es daran liegen?
Was ich so komisch finde ist ja, dass New das gleiche bewirkt als wenn ich das Formular Automatisch erzeugen lasse. Bei New funktioniert es aber nicht. Wenn ich es automatisch erzeugen lasse klappt es aber.
-
Guten Morgen,
Wenn du "Automatisch erzeugen" wählst, wird der Zeiger noch vor dem Start der eigentlichen Applikation (Applicatio->Run()) initialisiert. Dann muß es natürlich gehen.
Du hast doch mit Sicherheit mehrer Forms. Wo genau ist denn dieser Aufruf den du unten gepostet hast? in welchem OnCreate hast du Breakpoints gesetzt?
Ohne mehr Code kann man schwerlich etwas sagen. Wenn der zu umfangreich ist kannst du ihn mir auch zumailen.Ciao
-
Also hier ist mal das MainForm. Dort ist auch der Aufruf für die momentan drei Forms.
//--------------------------------------------------------------------------- #include <vcl.h> #pragma hdrstop #include "main_cpp.h" #include "artikel_anlegen_cpp.h" #include "About.h" #include "kunden_anlegen_cpp.h" #include "lagerplatz_anlegen_cpp.h" #include "funktionen.h" #include "Unit1.h" //--------------------------------------------------------------------------- #pragma resource "*.dfm" Thauptmenu *hauptmenu; //--------------------------------------------------------------------------- __fastcall Thauptmenu::Thauptmenu(TComponent *Owner) : TForm(Owner) { } //--------------------------------------------------------------------------- void __fastcall Thauptmenu::HelpAbout1Execute(TObject *Sender) { info->ShowModal(); } //--------------------------------------------------------------------------- void __fastcall Thauptmenu::FileExit1Execute(TObject *Sender) { Close(); } //--------------------------------------------------------------------------- void __fastcall Thauptmenu::Artikelanlegen1Click(TObject *Sender) { bool gefunden=false; //Überprüfen ob das MDIChild besteht for (int i = MDIChildCount - 1; i >= 0; i--) { if ((AnsiString)MDIChildren[i]->ClassName() == "Tartikel_anlegen") { MDIChildren[i]->Show(); gefunden=true; } } if (!gefunden) {//Artikel anlegen // Tartikel_anlegen *artikel_anlegen = new Tartikel_anlegen(Application); //Hier hatte ich einen Breakpoint artikel_anlegen = new Tartikel_anlegen(Application); artikel_anlegen->WindowState =wsMaximized; artikel_anlegen->Show(); } } //--------------------------------------------------------------------------- void __fastcall Thauptmenu::Kundenanlegen1Click(TObject *Sender) { bool gefunden=false; //Überprüfen ob das MDIChild besteht for (int i = MDIChildCount - 1; i >= 0; i--) { if ((AnsiString)MDIChildren[i]->ClassName() == "Tkunden_anlegen") { MDIChildren[i]->Show(); gefunden=true; } } if (!gefunden) {//Kunden anlegen // Tkunden_anlegen *kunden_anlegen = new Tkunden_anlegen(Application); kunden_anlegen = new Tkunden_anlegen(Application); kunden_anlegen->Show(); } } //--------------------------------------------------------------------------- void __fastcall Thauptmenu::Lagerplatzanlegen1Click(TObject *Sender) { bool gefunden=false; //Überprüfen ob das MDIChild besteht for (int i = MDIChildCount - 1; i >= 0; i--) { if ((AnsiString)MDIChildren[i]->ClassName() == "Tlagerplatz_anlegen") { MDIChildren[i]->Show(); gefunden=true; } } if (!gefunden) {//Lagerplatz anlegen // Tlagerplatz_anlegen *lagerplatz_anlegen = new Tlagerplatz_anlegen(Application); lagerplatz_anlegen = new Tlagerplatz_anlegen(Application); lagerplatz_anlegen->Show(); } } //--------------------------------------------------------------------------- void __fastcall Thauptmenu::FormActivate(TObject *Sender) { //dbconnect(); } //---------------------------------------------------------------------------Die Breakpoints habe ich im OnCreate oder OnActivate des artikel_anlegen Forms gesetzt.
Hier mal der Code dazu:
//--------------------------------------------------------------------------- #include <vcl.h> #pragma hdrstop #include "artikel_anlegen_cpp.h" #include "funktionen.h" #include "Unit1.h" //--------------------------------------------------------------------------- #pragma package(smart_init) #pragma resource "*.dfm" Tartikel_anlegen *artikel_anlegen; //--------------------------------------------------------------------------- __fastcall Tartikel_anlegen::Tartikel_anlegen(TComponent* Owner) : TForm(Owner) { } //--------------------------------------------------------------------------- void __fastcall Tartikel_anlegen::FormActivate(TObject *Sender) { AnsiString sql_select; //Anlegen der Auswahlmenüs für den Kunden und den Lagerplatz //dbconnect(); sql_select = "select * from kunden order by firma"; DataModule1->sql_kunden->SQL->Clear(); DataModule1->sql_kunden->SQL->Add(sql_select); DataModule1->sql_kunden->Open(); DataModule1->sql_kunden->First(); CBkunde->Clear(); if(DataModule1->sql_kunden->RecordCount != 0) { for (int i = 0; i < DataModule1->sql_kunden->RecordCount; i++) { CBkunde->Items->Add(DataModule1->sql_kunden->FieldByName("firma")->AsString); DataModule1->sql_kunden->Next(); } } else { CBkunde->Items->Add("Kunden anlegen"); } sql_select = "select * from lagerplatze order by bezeichnung"; DataModule1->sql_kunden->SQL->Clear(); DataModule1->sql_kunden->SQL->Add(sql_select); DataModule1->sql_kunden->Open(); DataModule1->sql_kunden->First(); CBlagerplatz->Clear(); if(DataModule1->sql_kunden->RecordCount != 0) { for (int i = 0; i < DataModule1->sql_kunden->RecordCount; i++) { CBlagerplatz->Items->Add(DataModule1->sql_kunden->FieldByName("bezeichnung")->AsString); DataModule1->sql_kunden->Next(); } } else { CBkunde->Items->Add("Lagerplatz anlegen"); } //dbdisconnect(); //Hier hatte ich einen Breakpoint artikel_anlegen->Label15->Caption = "test"; } //--------------------------------------------------------------------------- void __fastcall Tartikel_anlegen::FormClose(TObject *Sender, TCloseAction &Action) { Action = caFree; } //--------------------------------------------------------------------------- void __fastcall Tartikel_anlegen::FormCreate(TObject *Sender) { //Hier hatte ich einen Breakpoint DBlagerplatze_temp->Columns->Items[0]->Title->Caption = "Artikel-Nr."; //artikel_anlegen->DBlagerplatze_temp->Columns->Items[1]->Title->Caption = "Lagerplatz"; //artikel_anlegen->DBlagerplatze_temp->Columns->Items[2]->Title->Caption = "Menge auf Lagerplatz"; //artikel_anlegen->DBlagerplatze_temp->Columns->Items[3]->Title->Caption = "Palettenanzahl"; //artikel_anlegen_dbfelder(); } //--------------------------------------------------------------------------- void __fastcall Tartikel_anlegen::Button8Click(TObject *Sender) { DataModule1->sql_lagerplatze_artikel->Active = false; DataModule1->sql_lagerplatze_artikel->Active = true; artikel_anlegen_dbfelder(); } //---------------------------------------------------------------------------Gruß
-
artikel_anlegen ist eine globale Variable. Wenn du jetzt new in der Hauptform aufrufst wird eine Innstanz von Tartikel_anlegen erzeugt. Dabei wird auch OnCreate aufgerufen. Zu diesem Zeitpunkt ist der Zeiger artikel_anlegen aber noch nicht gültig. OnCreate sollte man sowieso nicht verwenden. Wenn überhaupt, sollte derartiger Code im Konstruktor ausgeführt werden.
1. Verlagere den Code aus OnCreate nach OnShow (wenn möglich)
2. lass innerhalb von artikel_anlegen.cpp bei Zugriffen auf dessen Membervariablen artikel_anlegen-> weg. Wenn du unbedingt willst kannst du das durch this-> ersetzen (ist aber nicht nötig).z.Bsp so
void __fastcall Tartikel_anlegen::FormCreate(TObject *Sender) { //Hier hatte ich einen Breakpoint DBlagerplatze_temp->Columns->Items[0]->Title->Caption = "Artikel-Nr."; // statt //artikel_anlegen->DBlagerplatze_temp->Columns->Items[1]->Title->Caption = "Lagerplatz"; //artikel_anlegen->DBlagerplatze_temp->Columns->Items[2]->Title->Caption = "Menge auf Lagerplatz"; //artikel_anlegen->DBlagerplatze_temp->Columns->Items[3]->Title->Caption = "Palettenanzahl"; // lieber DBlagerplatze_temp->Columns->Items[1]->Title->Caption = "Lagerplatz"; DBlagerplatze_temp->Columns->Items[2]->Title->Caption = "Menge auf Lagerplatz"; DBlagerplatze_temp->Columns->Items[3]->Title->Caption = "Palettenanzahl"; //artikel_anlegen_dbfelder(); }
-
Ich wollte ja das
DBlagerplatze_temp->Columns->Items[0]->Title->Caption = "Artikel-Nr."; DBlagerplatze_temp->Columns->Items[1]->Title->Caption = "Lagerplatz"; DBlagerplatze_temp->Columns->Items[2]->Title->Caption = "Menge auf Lagerplatz"; DBlagerplatze_temp->Columns->Items[3]->Title->Caption = "Palettenanzahl"als funktion auslagern. Damit ich es von überall wieder aufrufen kann. Dort muß ich es aber so anlegen:
artikel_anlegen->DBlagerplatze_temp->Columns->Items[0]->Title->Caption = "Artikel-Nr."; artikel_anlegen->DBlagerplatze_temp->Columns->Items[1]->Title->Caption = "Lagerplatz"; artikel_anlegen->DBlagerplatze_temp->Columns->Items[2]->Title->Caption = "Menge auf Lagerplatz"; artikel_anlegen->DBlagerplatze_temp->Columns->Items[3]->Title->Caption = "Palettenanzahl"Im OnShow kann ich es auch nicht folgendermaßen
DBlagerplatze_temp->Columns->Items[0]->Title->Caption = "Artikel-Nr."; DBlagerplatze_temp->Columns->Items[1]->Title->Caption = "Lagerplatz"; DBlagerplatze_temp->Columns->Items[2]->Title->Caption = "Menge auf Lagerplatz"; DBlagerplatze_temp->Columns->Items[3]->Title->Caption = "Palettenanzahl"aufrufen. Kommt auch ein Zugriffsfehler.
Ich denke ich lass es jetzt und mache es so wie du vorgeschlagen hast. Ist das einfachste.
Ich danke die für deine Hilfe und Geduld mit mir. :p
-
Wenn du es in eine Funktion auslagern willst, übergib ihr doch einfach den Zeiger.
void __fastcall setDBLager(Tartikel_anlegen* artikel) { artikel->DBlagerplatze_temp->Columns->Items[0]->Title->Caption = "Artikel-Nr."; artikel->DBlagerplatze_temp->Columns->Items[1]->Title->Caption = "Lagerplatz"; artikel->DBlagerplatze_temp->Columns->Items[2]->Title->Caption = "Menge auf Lagerplatz"; artikel->DBlagerplatze_temp->Columns->Items[3]->Title->Caption = "Palettenanzahl"; }Dieser Zeiger muß natürlich gültig sein. Diese Funktion braucht dann auch nicht Member einer Klasse zu sein. Nur die Deklaration von Tartikel_anlegen muß dort bekannt sein.