Entwickler-Ecke
Grafische Benutzeroberflächen (VCL & FireMonkey) - Formulare aufrufen
Mathematiker - Do 01.08.13 22:15
Titel: Formulare aufrufen
Hallo,
ich stehe wieder mal vor einem Problem, dass ich nicht lösen kann, da ich eigentlich nur mit "Versuch und Irrtum" experimentiere und die Theorie nicht kapiere.
In einem Programm habe ich sehr viele Formulare, die ich nicht zum Programmstart erzeugen möchte. Bisher rufe ich sie mit z.B.
Delphi-Quelltext
1: 2: 3:
| Application.CreateForm(TFinteraktiv, Finteraktiv); finteraktiv.showmodal; finteraktiv.release; |
auf. Das funktioniert, gefällt mir aber bei den mehr als 50 Formularen nicht. Irgendwie ist das zu "umständlich".
Deshalb dachte ich, eine allgemeine Methode zu schreiben. Meine Idee war etwas in der Art
Delphi-Quelltext
1:
| procedure aufrufen(form:tform); |
bei der ich die Bezeichnung des Formulars übergebe und in der Methode die Klasse für Createform ermittelt wird. Leider weiß ich nicht, was ich dort tun soll. Null Ahnung.
Daher habe ich es mit
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12:
| procedure rufen(tform:tformclass; form:tform); begin Application.CreateForm(tForm, Form); form.showmodal; form.release; end; ... case formularnr of 1 : rufen(TFinteraktiv, Finteraktiv); 2 : rufen(TFanalysis, Fanalysis); ... end; |
versucht. Und nun tritt das Problem auf. Das Programm fliegt mir bei jedem Aufruf mit einer Access Violation um die Ohren. So geht es also nicht und ich bin wieder eine Erfahrung reicher, dass ich eigentlich die Delphi-Grundlagen mal lernen müsste.
Natürlich ist mir klar, dass der Aufwand für nur je zwei gesparte Befehle je Formularaufrufe unverhältnismäßig ist, aber jetzt interessiert es mich schon aus Prinzip.
Kann mir jemand von Euch helfen? Danke.
Beste Grüße
Mathematiker
IhopeonlyReader - Do 01.08.13 22:20
Benenne doch mal tform um.. Tform ist soviel ich weiß eine Klasse und sollte nicht für eine variable missbraucht werden ;) ob das der Fehler ist weiß ich nicht
Mathematiker - Do 01.08.13 22:24
Hallo,
IhopeonlyReader hat folgendes geschrieben : |
Benenne doch mal tform um.. Tform ist soviel ich weiß eine Klasse und sollte nicht für eine variable missbraucht werden ;) |
Danke. Ich bin so blöd. :autsch: :autsch: :autsch:
Wie kann ich tform als Variable benutzen? Aber es ändert nichts am Absturz, nachdem ich tform:tformclass in xform:tformclass umbenannt habe. Leider.
Beste Grüße
Mathematiker
IhopeonlyReader - Do 01.08.13 22:26
Ein anderer Fehler könnte es sein, dass Klassen ja pointer sind.. Deshalb brauch man eig kein var davor schreiben, aber in deinem Sonderfall ist die Variable noch Nil.. Setzte deshalb mal ein var davor, da du dem
Pointer eine speicheradresse zuweist und nichts in der Klasse änderst..
Mathematiker - Do 01.08.13 22:29
Alle drei Möglichkeiten:
Delphi-Quelltext
1: 2: 3:
| procedure rufen(var xform:tformclass; var form:tform); procedure rufen(var xform:tformclass; form:tform); procedure rufen(xform:tformclass; var form:tform); |
werden von Delphi gar nicht erst übersetzt. Schade.
Beste Grüße
Mathematiker
IhopeonlyReader - Do 01.08.13 22:32
Und wenn du die Parameter deiner procedure exakt so machst wie die Parameter von Applikation.formcreate
Wenn Du die klammer auf machst, siehst du ja was wie verlangt wird ;)
Mathematiker - Do 01.08.13 22:39
IhopeonlyReader hat folgendes geschrieben : |
Und wenn du die Parameter deiner procedure exakt so machst wie die Parameter von Applikation.formcreate |
Habe ich versucht. Bei
Delphi-Quelltext
1:
| rufen(FormClass: TFormClass; var Reference) |
kann ich aber "Reference" nicht nutzen. Dann wird zwar
Delphi-Quelltext
1:
| Application.CreateForm(Formclass, reference); |
übersetzt, aber nicht
Delphi-Quelltext
1: 2:
| reference.showmodal; reference.release; |
Ich weiß wieder nicht, was ich hier eigentlich tue. :autsch:
Beste Grüße
Mathematiker
IhopeonlyReader - Do 01.08.13 22:41
Tform(reference).showmodal
Oder
(Reference as tform).showmodal
?
Mathematiker - Do 01.08.13 22:44
Hallo,
Das war es. Danke!
Mit
Delphi-Quelltext
1: 2: 3: 4: 5: 6:
| procedure rufen(FormClass: TFormClass; var Reference); begin Application.CreateForm(Formclass, reference); tform(reference).showmodal; tform(reference).release; end; |
klappt alles wunderbar. Allerdings muss ich jetzt mal noch sehen, ob mehrere Formulare aufrufbar sind und was FastMM4 dazu sagt.
Beste Grüße
Mathematiker
jaenicke - Do 01.08.13 23:45
Sauberer und einfacher geht es so:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14:
| procedure ShowForm(const AFormClass: TFormClass); var MyForm: TForm; begin MyForm := AFormClass.Create(nil); try MyForm.ShowModal; finally MyForm.Free; end; end;
ShowForm(TForm266); |
// EDIT:
Übrigens geht auch so etwas:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21:
| procedure ShowForm(const AFormClass: String); var MyForm: TForm; begin MyForm := TFormClass(FindClass(AFormClass)).Create(nil); try MyForm.ShowModal; finally MyForm.Free; end; end;
procedure TForm265.FormCreate(Sender: TObject); begin RegisterClass(TForm266); end;
procedure TForm265.Button1Click(Sender: TObject); begin ShowForm('TForm266'); end; |
Mathematiker - Fr 02.08.13 00:00
Hallo jaenicke,
Danke für die Hinweise.
Ich habe beides ausprobiert und leider tritt bei beiden Varianten an den Stellen
Delphi-Quelltext
1: 2: 3:
| MyForm := AFormClass.Create(nil); bzw. MyForm := TFormClass(FindClass(AFormClass)).Create(nil); |
ein Programmabsturz auf. Könnte es an meinem Delphi 5 liegen?
Beste Grüße
Mathematiker
IhopeonlyReader - Fr 02.08.13 00:00
Delphi-Quelltext
1: 2: 3: 4: 5: 6:
| With aformclass.create(Nil) Do Try Showmodal; Finally Free; End; |
Ebenso möglich.. Dann würde man sich 4Byte RAM sparen ;) und müsste sich nicht mit variablen eines abstrakten klasse beschäftigen, dass oft zu Fehlern führt
Mathematiker - Fr 02.08.13 00:10
Hallo,
ich weiß, warum jaenickes Vorschlag bei mir abstürzte.
In den Methoden von TFinteraktiv habe ich z.B. mit
Delphi-Quelltext
1: 2: 3:
| finteraktiv.width:=formx; finteraktiv.height:=formy; finteraktiv.caption:=aktuellname2; |
Werte des Formulars geändert. Verwende ich
Delphi-Quelltext
1: 2: 3:
| width:=formx; height:=formy; caption:=aktuellname2; |
funktioniert es einwandfrei.
Beste Grüße
Mathematiker
IhopeonlyReader - Fr 02.08.13 00:12
Hast du meins probiert?
Oft gibt es Probleme mit abstrakten Klassen..,
Mathematiker - Fr 02.08.13 00:22
Hallo,
Delphi-Quelltext
1: 2: 3: 4: 5: 6:
| With aformclass.create(Nil) Do Try Showmodal; Finally Free; End; |
ergibt ebenso Probleme, wenn ich in den Methoden Eigenschaften des Formulars in der Form finteraktiv.xxxxx:= ändern will. Ist ja eigentlich auch logisch.
Unklar ist für mich nur noch, ob ich durch das Weglassen von "finteraktiv." mit width, height, caption, ... auch wirklich immer die Eigenschaften des Formulars erhalte und nicht die von irgendeinem enthaltenen Objekt wie TPanel, TPaintbox, ...
Beste Grüße
Mathematiker
IhopeonlyReader - Fr 02.08.13 00:27
Wenn Du das finteraktiv weglässt wird die variable Der Klasse genommen..
Auto: tauto
Pkw:tauto;
Procedure tauto.Test;
Begin
Auto.Reifen := 4;
Reifen := 5;
End;
Auto.Test dann hat Auto 5 Reifen
Pkw.Test dann hat Auto 4 Reifen und Pkw 5
Verstehst du? Aber wehe Auto wurde vor dem Aufruf von Pkw.Test nicht erzeugt..
jaenicke - Fr 02.08.13 06:49
IhopeonlyReader hat folgendes geschrieben : |
Ebenso möglich.. Dann würde man sich 4Byte RAM sparen ;) und müsste sich nicht mit variablen eines abstrakten klasse beschäftigen, dass oft zu Fehlern führt |
Was du gepostet hast, ergibt exakt den gleichen Code... ob du die Variable nun explizit anlegst oder mit with versteckt ändert doch am Speicher nichts...
Und was Fehler angeht, da ist with eine der größten Fehlerquellen, die es in Delphi gibt... :roll:
Aus den Quelltexten von Delphi selbst wurde es nicht umsonst eliminiert und in der Hilfe wird von der Benutzung mittlerweile ebenfalls abgeraten.
Vor allem beim späteren Überarbeiten von Quelltexten oder schon bei einer neuen Delphiversion verursacht das massive Probleme. Denn man erkennt innerhalb eines with nicht was wozu gehört, so dass man bei einer Änderung des Quelltextes sehr aufpassen muss was man tut und teilweise trotz Aufpassen nicht so einfach sehen kann was wozu gehört. Als Beispiel hier ein Auszug aus einer älteren Version der VirtualStringTrees:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7:
| procedure TBaseVirtualTree.StaticBackground(Source: TBitmap; Target: TCanvas; Offset: TPoint; R: TRect); begin ... with DrawRect do MaskBlt(Target.Handle, Left - Offset.X, Top - Offset.Y, (Right - Offset.X) - (Left - Offset.X), (Bottom - Offset.Y) - (Top - Offset.Y), Source.Canvas.Handle, Left - PicRect.Left, DrawRect.Top - PicRect.Top, Source.MaskHandle, Left - PicRect.Left, Top - PicRect.Top, MakeROP4(DST, SRCCOPY)); |
In einer neuen Delphiversion hatte ein TRect nun plötzlich selbst eine Prozedur Offset drin und schwupps, schon bezog sich Offset durch das with nicht mehr auf den Parameter Offset, sondern auf diese Prozedur...
An der Stelle gab es zum Glück einen Fehler beim Kompilieren, aber an anderen Stellen wurde so plötzlich Width von TRect benutzt statt vom Formular, in dem man das aufgerufen hatte. Das resultierte dann in schwer zu findenden Fehlern...
Wenn ich dran denke wie viele Stunden wir bei der Arbeit schon mit with-Fehlern verbracht haben... da wird mir schlecht. Aber es dauert halt das überall nach und nach auszubauen...
IhopeonlyReader - Fr 02.08.13 22:01
Klappt es denn mit self. (anstatt finteraktiv oder. Ganz ohne)?
Self ist der "aufrufer" also als wenn du es weglassen würdest, falls es aber Reifen und in der Klasse tauto Reifen gibt dann verwende lieber self.Reifen in dertAuto procedure
jaenicke - Fr 02.08.13 22:37
IhopeonlyReader hat folgendes geschrieben : |
Klappt es denn mit self. (anstatt finteraktiv oder. Ganz ohne)? |
Nein, denn Parameter kann man damit nicht ansprechen. Es gibt in dem Fall keine andere Lösung als das with zu entfernen oder den Parameter umzubenennen. Ob dann mit dem nächsten Delphiupgrade der nächste Begriff umbenannt werden muss, weißt du aber immer noch nicht... und den umbenannten Begriff gibt es dann ggf. auch wieder.
Letztlich ist alles was den Scope unklar macht, und das tut with eben, Gift für sauberen Quelltext. Denn normalerweise ist genau geregelt in welcher Reihenfolge Begriffe gesucht werden und ob in irgendeiner Klasse oder irgendwo anders etwas dazukommt, ist egal. With sorgt dafür, dass eben diese Reihenfolge außer Kraft gesetzt werden kann.
Davon abgesehen ist der einzige Vorteil von with das Sparen von ein paar Buchstaben Schreibarbeit. Wer sich davor scheut, hat sich als Softwareentwickler schlicht den falschen Beruf ausgesucht.
jfheins - Fr 02.08.13 22:50
Mathematiker hat folgendes geschrieben : |
Hallo,
Unklar ist für mich nur noch, ob ich durch das Weglassen von "finteraktiv." mit width, height, caption, ... auch wirklich immer die Eigenschaften des Formulars erhalte und nicht die von irgendeinem enthaltenen Objekt wie TPanel, TPaintbox, ... |
Solange du kein with benutzt: wahrscheinlich schon. Deine Event-Handler sehen ja meistens so ähnlich aus:
Delphi-Quelltext
1: 2: 3: 4:
| procedure TMeinFormular.Button1Click(Sender: TObject) begin showmessage(IntToStr(Width)); end; |
Das Width bezieht sich nun immer auf die konkrete Instanz von TMeinFormular. Das ist ja auch eine Methode dieses Formulars, wie du daran erkennst, dass der Klassenname vor dem Methodennamen steht.
Der Parameter Sender bezieht sich hingegen auf den Button/Panel/Whatever welches das Event ausgelöst hat.
Das ändert sich natürlich in dem Moment, in dem du Methoden betrachtest die nicht zu einem Formular gehören.
Mathematiker - Fr 02.08.13 23:07
Hallo,
jfheins hat folgendes geschrieben : |
Solange du kein with benutzt: wahrscheinlich schon. |
Danke für den Hinweis.
Was mich trotzdem noch vorsichtig werden lässt, ist das "wahrscheinlich".
Mir ist eigentlich klar, dass width, height usw. sich dann auf TMeinFormular beziehen, aber ich habe eine ungutes Gefühl. Gebe ich MeinFormular.width an, ist es eindeutig.
Der Vorschlag von
IhopeonlyReader mit self.width usw. wird übersetzt und scheinbar korrekt ausgeführt.
Aber auch da ist mein Gefühl nicht besser.
Irgendwie habe ich in diesem Zusammenhang kein Vertrauen zum Compiler. Zu viele schlechte Erfahrungen, zu geringe Kenntnisse oder aber eine Art Paranoia? Wahrscheinlich alles! :nixweiss:
Beste Grüße
Mathematiker
jaenicke - Fr 02.08.13 23:20
Mathematiker hat folgendes geschrieben : |
Gebe ich MeinFormular.width an, ist es eindeutig. |
Aber nicht immer richtig... was, wenn du noch im Konstruktor bist und die Formularvariable dementsprechend noch nicht zugewiesen? Was, wenn du das selbe Formular mehrfach benutzt? (in der Variable würde dann ja nur eines der Formulare liegen...)?
Mathematiker hat folgendes geschrieben : |
Der Vorschlag von IhopeonlyReader mit self.width usw. wird übersetzt und scheinbar korrekt ausgeführt.
Aber auch da ist mein Gefühl nicht besser. |
Self ist die einzige Möglichkeit dich auf das aktuelle Objekt zu beziehen. Du kannst es aber auch weglassen solange du kein with benutzt.
Mathematiker hat folgendes geschrieben : |
Irgendwie habe ich in diesem Zusammenhang kein Vertrauen zum Compiler. Zu viele schlechte Erfahrungen, zu geringe Kenntnisse oder aber eine Art Paranoia? |
Wenn du with benutzt, ist das kein Wunder...
Das hat aber nichts mit Vertrauen zum Compiler oder einem unzuverlässigen Compiler zu tun, sondern einfach mit schlechtem Code, weil with drin benutzt wird...
Ohne with ist ganz klar, dass der Reihe nach von nahe dran (lokale Variablen, ...) angefangen nach außen (aktuelles Objekt, globale Variablen, ...) gesucht wird. Und das verhält sich auch immer gleich.
jfheins - Fr 02.08.13 23:24
Zitat: |
ist das "wahrscheinlich". |
Das
wahrscheinlich bezog sich auf die Sache mit anderen Klassen. Sofern du in Methoden des Formulars bist und kein with...do benutzt, bezieht sich self (oder eben weglassen) immer auf selbiges Formular.
Das Gegenteil ist der Fall :D
Schreibst du sowas:
Delphi-Quelltext
1: 2: 3: 4:
| procedure TMeinFormular.ResetHeight() begin MeinFormular.Height = 700; end; |
Dann ist das eigentlich
falscher Code. Weil wenn ich das hier mache:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7:
| procedure TMainForm.ButtonClick(Sender: TObject) var formular: TMeinFormular; begin formular := TMeinFormular.Create(); formular.ResetHeight(); end; |
Dann produziert das entweder eine AV oder es macht etwas falsches.
Mathematiker - Fr 02.08.13 23:29
Hallo jaenicke,
Hallo jfheins,
ihr habt mich überzeugt. Da ich with seit einiger Zeit nicht mehr verwende, gibt es also keine Probleme.
Danke an beide.
Als nächstes werde ich einige Formulare etwas umstellen und die Fehler entfernen müssen, da ich jedes Mal so etwas wie MeinFormular.Caption ... nutze. :autsch:
Beste Grüße
Mathematiker
Entwickler-Ecke.de based on phpBB
Copyright 2002 - 2011 by Tino Teuber, Copyright 2011 - 2025 by Christian Stelzmann Alle Rechte vorbehalten.
Alle Beiträge stammen von dritten Personen und dürfen geltendes Recht nicht verletzen.
Entwickler-Ecke und die zugehörigen Webseiten distanzieren sich ausdrücklich von Fremdinhalten jeglicher Art!