![]() |
Objekte zur Laufzeit erzeugen
Hi DP
Meine Überschrift trift es nicht ganz da ich ja schon einmal etwas in der Richtung gefragt hatte nur hat das jetzt nichts damit zu tun. Mein Problem: Ich möchte auf einem zweiten Formular zum Programm start Buttons erzeugen nur, da das Fenster noch nicht erzeugt ist, bekomme ich folgende Fehlermeldung:
Code:
Ich habe das zweite Formular aus der Erstellungsreihenfolge herausgenommen und will es selbst erzeugen mit Form.Create nur bekomme ich dabei den Fehler.
Im Projekt Projekt1.exe ist eine Exception der Klasse $C0000005 mit der Meldung 'access violation at 0x006c439b: read of address 0x000003e0' aufgetreten
Hier ist mein Code:
Delphi-Quellcode:
Danke im Voraus.
unit open;
interface uses Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.Grids, Vcl.ValEdit, Vcl.StdCtrls, Vcl.ExtCtrls, Vcl.DBCtrls, Vcl.DBGrids, Data.DB, Datasnap.DBClient; type TFrmOpen = class(TForm) Button1: TButton; Button2: TButton; DS: TDataSource; CDS: TClientDataSet; CDSspeise: TStringField; CDSpreis: TFloatField; DBGrid1: TDBGrid; DBNavigator1: TDBNavigator; procedure Button1Click(Sender: TObject); procedure FormCreate(Sender: TObject); procedure Button2Click(Sender: TObject); procedure GenerateButton; private { Private-Deklarationen } LBe: Boolean; LBut: array of TButton; public { Public-Deklarationen } end; var FrmOpen: TFrmOpen; implementation {$R *.dfm} uses scan, use; procedure TFrmOpen.Button1Click(Sender: TObject); begin if not LBe then begin FrmOpen.Width := 609; LBe := true; end else begin FrmOpen.Width := 369; Lbe:= false; end; end; procedure TFrmOpen.Button2Click(Sender: TObject); begin FrmScan.Show; end; procedure TFrmOpen.FormCreate(Sender: TObject); begin Lbe := false; CDS.FileName := 'custom.xml'; if FileExists(CDS.FileName) then begin CDS.LoadFromFile(CDS.FileName); GenerateButton; end else begin CDS.CreateDataSet; end; end; procedure TFrmOpen.GenerateButton; var i: Integer; begin CDS.First; for i := 0 to CDS.RecNo do begin LBut[i] := TButton.Create(FrmUse.BoxScro); LBut[i].Parent := FrmUse.BoxScro; LBut[i].Left := 20 + ((LBut[i].Height + 10) * i); LBut[i].Height := 20; if (i >= 5) then LBut[i].Height := 20 + ((LBut[i].Height + 10) * i); LBut[i].Caption := CDS.FieldByName('test').Value; CDS.Next; end; end; end. Luki :spin: |
AW: Objekte zur Laufzeit erzeugen
Zitat:
Ich finde das Form.Create garnicht. Und sicher daß du Form.Create meinst und nicht TForm.Create? |
AW: Objekte zur Laufzeit erzeugen
ja ich meinte TForm.Create und komischer weise ist das jetzt verschwunden :shock: :gruebel: jetzt ist's richtig:
Delphi-Quellcode:
es war nur in der procedure. Jetzt setzt er den Pointer bei
procedure TFrmOpen.FormCreate(Sender: TObject);
begin Lbe := false; CDS.FileName := 'custom.xml'; if FileExists(CDS.FileName) then begin CDS.LoadFromFile(CDS.FileName); TFrmUse.Create(self); GenerateButton; end else begin CDS.CreateDataSet; end; end;
Code:
als Fehler
LBut[i] := TButton.Create(FrmUse.BoxScro);
|
AW: Objekte zur Laufzeit erzeugen
Und wann wird der Wert von
Delphi-Quellcode:
gesetzt?
FrmUse
|
AW: Objekte zur Laufzeit erzeugen
Ich weiß gerade nicht was du mit 'Wert' meinst? :gruebel:
|
AW: Objekte zur Laufzeit erzeugen
FrmUse ist doch eine Variable, nicht wahr? Variablen kann man Werte zuweisen, wenn ich mich nicht irre. In deinem Code findet diese Zuweisung nicht statt. Du greifst aber auf FrmUse zu, was dann einen Fehler auslöst.
Übrigens: Meines Wissens nach hat man dir schon gefühlte hundert Mal dringend empfohlen, deinen Quellcode ordentlich zu formatieren. Das kann ja kein Mensch entziffern! Wieso ignorierst du das nach 8 Monaten in diesem Forum noch immer hartnäckig? |
AW: Objekte zur Laufzeit erzeugen
Liste der Anhänge anzeigen (Anzahl: 1)
Ich hab hier eine Funktion aus einem meiner Projekte rauskopiert (und angepasst), die auch Fenster dynamisch erzeugt. Die "Blaupause" für die Formulare (man kann unendlich davon erzeugen) wird nicht automatisch erzeugt, sondern ist nur verfügbar.
|
AW: Objekte zur Laufzeit erzeugen
Ok danke, aber das trift es jetzt auch nicht ganz.. Ich habe jetzt noch einmal etwas ausprobiert bei dem beim erscheinen des Formulars die Komponenten erzeugt werden. Nur bekomme ich bei den Buttons also bei
Delphi-Quellcode:
den Fehler den ich oben beschrieben habe.
LBut[i] := TButton.Create(ScrollBox);
@Perlsau: ich habe es eigentlich versucht einen 'ordentlichen' Code zu schreiben.. Was genau ist das was man fast nicht entziffern kann? :gruebel: PS: Hier ist die procedure die ich ausführe wenn das Fenster sichtbar wird:
Delphi-Quellcode:
Ich erzeuge auch gleich eine ScrollBox nur das ist nicht das Problem... Oder sollte ich gleich das ganze Projekt hochladen?
procedure TFrmUse.GenerateButton;
var i: Integer; begin BoxScro := TScrollBox.Create(TabAbrech); BoxScro.Align := alClient; BoxScro.BorderStyle := bsNone; FrmOpen.CDS.First; for i := 1 to FrmOpen.CDS.RecNo do begin LBut[i] := TButton.Create(BoxScro); LBut[i].Parent := BoxScro; LBut[i].Left := 20 + ((LBut[i].Height + 10) * i); LBut[i].Height := 20; if (i >= 5) then LBut[i].Height := 20 + ((LBut[i].Height + 10) * i); LBut[i].Caption := FrmOpen.CDS.FieldByName('speise').Value; FrmOpen.CDS.Next; end; end; |
AW: Objekte zur Laufzeit erzeugen
-BoxScro hat keinen Parent.
-Wann wird frmUse erzeugt? -Wo und wie ist LBut[] delartiert? ... |
AW: Objekte zur Laufzeit erzeugen
Delphi-Quellcode:
unit Unit1;
... implementation uses Unit2; {$R *.dfm} procedure TForm1.Button1Click(Sender: TObject); begin Form2.GenerateButton; Form2.Show; end;
Delphi-Quellcode:
unit Unit2;
interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, ComCtrls, ExtCtrls; type TForm2 = class(TForm) PageControl1: TPageControl; TabAbrech: TTabSheet; procedure FormCreate(Sender: TObject); private { Private-Deklarationen } BoxScro: TScrollBox; LBut: array[0..3] of TButton; public { Public-Deklarationen } procedure GenerateButton; end; var Form2: TForm2; implementation {$R *.dfm} procedure TForm2.GenerateButton; var i: Integer; begin BoxScro := TScrollBox.Create(TabAbrech); BoxScro.Parent := TabAbrech; //<<<<<<<<<<<<<<<<<<<<< BoxScro.Align := alClient; BoxScro.BorderStyle := bsNone; //FrmOpen.CDS.First; for i := 1 to High(Self.LBut) do //FrmOpen.CDS.RecNo do begin LBut[i] := TButton.Create(BoxScro); LBut[i].Parent := BoxScro; LBut[i].Left := 20 + ((LBut[i].Height + 10) * i); LBut[i].Height := 20; if (i >= 5) then LBut[i].Height := 20 + ((LBut[i].Height + 10) * i); LBut[i].Caption := IntToStr(LBut[i].Left); // FrmOpen.CDS.FieldByName('speise').Value; //FrmOpen.CDS.Next; end; end; procedure TForm2.FormCreate(Sender: TObject); begin PageControl1.Align := alClient; end; end. |
AW: Objekte zur Laufzeit erzeugen
-BoxScro hat jetzt einen Parent
-FrmUse steht in der Erstellungsreihenfolge als zweites und wird durch FrmUse.Show; aufgerufen -LBut liegt in private und ist so deklariert:
Code:
LBut: array of TButton;
|
AW: Objekte zur Laufzeit erzeugen
Zitat:
Delphi-Quellcode:
setLength( LBut, FrmOpen.CDS.RecNo+1);
|
AW: Objekte zur Laufzeit erzeugen
Delphi-Quellcode:
Ist jetzt nicht zum eigentlichen Problem, weil mMn die Hälfte der Infos fehlen, die man bräuchte, um einen vernünftigen Rat zu erteilen. Daher nur zum obigen Codeschnipsel:
LBut[i].Left := 20 + ((LBut[i].Height + 10) * i);
LBut[i].Height := 20; if (i >= 5) then LBut[i].Height := 20 + ((LBut[i].Height + 10) * i); Wieso hängt die linke Position von der Höhe ab (die dazu erst noch in der nächsten Zeile gegeben wird? Wie wird die wohl vorher gewesen sein?). Button für i>5 werden größer??? Sollte hier Top gemeint sein??? |
AW: Objekte zur Laufzeit erzeugen
Ok ich habe alles jetzt noch einmal bearbeitet, habe die Länge des Array's gesetzt und habe auch die Fehler mit dem was Jumpy angesprochen hat beseitigt. Nur wird nur ein Button erzeugt. die prozedure sieht jetzt so aus:
Delphi-Quellcode:
procedure TFrmUse.GenerateButton;
var i: Integer; begin BoxScro := TScrollBox.Create(TabAbrech); BoxScro.Parent := TabAbrech; BoxScro.ParentBackground := true; BoxScro.Align := alClient; BoxScro.BorderStyle := bsNone; FrmOpen.CDS.First; for i := 1 to High(Self.LBut) do begin LBut[i] := TButton.Create(BoxScro); LBut[i].Parent := BoxScro; LBut[i].Left := 20 + 2*(i+1); LBut[i].Top := 30; if (i >= 5) then LBut[i].Top := 30 + 2*(i+1); LBut[i].Caption := FrmOpen.CDS.FieldByName('speise').Value; FrmOpen.CDS.Next; end; end; |
AW: Objekte zur Laufzeit erzeugen
Zitat:
|
AW: Objekte zur Laufzeit erzeugen
Zitat:
Delphi-Quellcode:
sagt muss auch
high
Delphi-Quellcode:
- äh
fisch
Delphi-Quellcode:
sagen.
low
Delphi-Quellcode:
for i := low( Self.LBut ) to high( Self.LBut ) do |
AW: Objekte zur Laufzeit erzeugen
Zitat:
Welche Breite haben die Buttons, wenn 2 pixel später schon der nächste beginnt? Und die Oberkante wird für i>5 immer größer?? |
AW: Objekte zur Laufzeit erzeugen
Zitat:
Delphi-Quellcode:
procedure TFrmUse.GenerateButton;
var i: Integer; begin BoxScro := TScrollBox.Create(TabAbrech); BoxScro.Parent := TabAbrech; BoxScro.ParentBackground := true; BoxScro.Align := alClient; BoxScro.BorderStyle := bsNone; FrmOpen.CDS.First; setLength( LBut, FrmOpen.CDS.RecNo+1); for i := 1 to FrmOpen.CDS.RecNo do begin LBut[i] := TButton.Create(BoxScro); LBut[i].Parent := BoxScro; ... FrmOpen.CDS.Next; end; end; |
AW: Objekte zur Laufzeit erzeugen
Ok danke, nur bekomme ich jetzt nur 2 Button..
|
AW: Objekte zur Laufzeit erzeugen
RecNo, nicht RecordCount? Ich persönlich würde aber sowieso einer Liste (TObjectList/TComponentList) den Vorzug geben, einfach mit First/Next über die Datenmenge iterieren und den neuen Button mit Add() der Liste hinzufügen, das ist weniger Gefummel und schneller dürfte es auch sein.
|
AW: Objekte zur Laufzeit erzeugen
Sind die Button wirklich nur 2*2 Pixel groß?
|
AW: Objekte zur Laufzeit erzeugen
Natürlich nicht :D habe jetzt das so gemacht:
Delphi-Quellcode:
Nur wie du das jetzt gemeint hattest bekomme ich jetzt immer noch nur ein Button oder hatte das einen anderen Sinn?
LBut[i].Left := 20 + (2*LBut[i].Width*i);
|
AW: Objekte zur Laufzeit erzeugen
Vorher wurden die Buttons im Abstand von 2 Pixeln plaziert.
Das selbige gilt natürlich auch für Top (senkrecht) Wieviele Einträge hat die Datenbank? |
AW: Objekte zur Laufzeit erzeugen
Jetzt hat sie vier aber das soll ja natürlich variabel sein
|
AW: Objekte zur Laufzeit erzeugen
Schau dir doch die Erzeugung Schritt für Schritt im Debugger an
|
AW: Objekte zur Laufzeit erzeugen
Hmm.. ich habe gerade ein Mysterium entdeckt das ich mir nicht erklären kann, wenn ich das Formular schließe und dann wieder öffne wird immer wieder ein Button erzeugt :shock:
Edit: Beim ausführen mit dem Debugger ist mir aufgefallen das er nur einmal die Schleife durchgeht und am Schluss dann zu end springt ohne weitere Knöpfe zu erstellen.. |
AW: Objekte zur Laufzeit erzeugen
Ich habe jetzt auch ein wenig herumgebastelt nur wird immer noch nur ein Button erzeugt. Wie müsste ich das machen das wirklich alle Buttons auf einmal erstellt werden?
|
AW: Objekte zur Laufzeit erzeugen
Die Anzahl deiner Buttons hängt ja offensichtlich von FrmOpen.CDS.RecNo ab. Es wäre also eine richtig gute Idee, einfach mal im Debugger zu schauen, welchen Wert diese Variable hat. Alles andere ist Rumraterei.
MfG Dalai |
AW: Objekte zur Laufzeit erzeugen
Sollte das mit Debuger zu kompliziert sein, einfach ein
Delphi-Quellcode:
nach
ShowMessage(IntToStr(i));
Delphi-Quellcode:
setzten. Man wird dann zwar ständig unterbrochen, wenn es sonst nicht klappt...
for i :=
|
AW: Objekte zur Laufzeit erzeugen
Liste der Anhänge anzeigen (Anzahl: 1)
Ok hat geklappt, lag an dem
Delphi-Quellcode:
es muss aber sein wie es DaddyH gesagt hatte mit
CDS.RecNo
Delphi-Quellcode:
sein. Geht jetzt :thumb:
CDS.RecordCount
Bekomme ich aber eine kleine Erklärung zum Debugger weil ich lese da nur irgendwelche Dollarzeichen mit Zahlen Edit: Weil ich habe auch noch nichts damit anfangen können |
AW: Objekte zur Laufzeit erzeugen
Das ist ja auch nur der Aufruf-Stack. Es gibt aber noch ein Fenster, wo du dir die Werte der lokalen Variablen ansehen kannst.
|
AW: Objekte zur Laufzeit erzeugen
Hmm.. Habe ich nicht bzw. ich finde diese nicht. Kann es sein dass das Fenster in der Starter herausgenommen wurde?
|
AW: Objekte zur Laufzeit erzeugen
Zitat:
![]() (oder du hast das Fenster ausgeblendet) Ok, laut Feature-Matrix (Seite 11) ist das nicht dabei (der gesamte Debugger ist gefühlt nicht dabei) |
AW: Objekte zur Laufzeit erzeugen
Liste der Anhänge anzeigen (Anzahl: 1)
Aus der Liste mit den Fenstern habe ich nur die ersten drei.. Dann ist das nicht dabei... Jetzt habe ich aber noch ein Problem. Wenn ich das Formular mit den darauf erzeugten Buttons aufrufe und wieder schließe passiert nichts nur erst wenn ich die komplette Anwendung beenden will bekomme ich eine Fehlermeldung mit Inhalt:
|
AW: Objekte zur Laufzeit erzeugen
Das ist auch nicht der Debugger
|
AW: Objekte zur Laufzeit erzeugen
Das beste für dich (@ TE) wäre STRG+ALT+L.
Damit rufst du Liste der lokalen Variablen inkl. Werten auf. Im Gegensatz zu Überwachte Ausdrücke STRG+ALT+W muss man bei lokalen Variablen nichts machen. Es werden einfach alle angezeigt. Übrigens, was nicht angezeigt wird, ist nicht da. Das Fenster zeigt nur Werte an die vorhanden sind, nicht aber die, die wegoptimiert wurden. |
AW: Objekte zur Laufzeit erzeugen
Zitat:
Delphi-Quellcode:
statt:
if Voraussetzung then do
begin MeinCode1; MeinCode2; end;
Delphi-Quellcode:
if Voraussetzung then do begin
MeinCode1; MeinCode2; end; |
AW: Objekte zur Laufzeit erzeugen
Zitat:
Und wenn nicht, dann muß er sich halt an das ShowMessage-Debugging gewöhnen, bzw. mit OutputDebugStrings+Ereignisprotokoll arbeiten. PS: Ich schreibe das Begin auch immer ans Ende, anstatt es "sinnlos" eine eigene Zeile besetzen zu lassen, ABER mit einer ordentlichen Einrückung gibt es da IMHO keinerlei Probleme damit.
Delphi-Quellcode:
Und nur weil das am Anfang steht, wird es nicht gleich übersichtlicher. :angel2:
if Voraussetzung then begin
MeinCode1; MeinCode2; end;
Delphi-Quellcode:
Ich würde ihm ja den delphieigenen Codeformatter empfehlen, aber auch den baute man aus der Starter aus. :wall: (wenn man es nicht selber hinbekommt: ab und an mal ein beherztes Strg+D und gut ist)
if Voraussetzung then
begin MeinCode1; MeinCode2; end; |
AW: Objekte zur Laufzeit erzeugen
Zitat:
Delphi-Quellcode:
if Voraussetzung then
begin MeinCode1; MeinCode2; end; |
AW: Objekte zur Laufzeit erzeugen
Da mir jetzt drei Leute das ein und selbe gesagt haben werde ich das berücksichtigen :mrgreen:
@Popov: Das mit dem STRG+ALT+L habe ich ja schon ausprobiert und es passiert einfach nichts weil die das ja leider ausgebaut hatten... :( Und was ist jetzt mit der Fehlermeldung die kommt wenn der Speicher freigegeben werden soll? |
Alle Zeitangaben in WEZ +1. Es ist jetzt 10:37 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz