Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   GUI-Design mit VCL / FireMonkey / Common Controls (https://www.delphipraxis.net/18-gui-design-mit-vcl-firemonkey-common-controls/)
-   -   Delphi Laufzeitfehler mit eigenem Typ (https://www.delphipraxis.net/133660-laufzeitfehler-mit-eigenem-typ.html)

64Jabor 6. Mai 2009 17:09


Laufzeitfehler mit eigenem Typ
 
Hallo DP,

ich möchte gerne zur Laufzeit meines Programmes eine eigene Klasse erstellen.
Diese Klasse soll einen Computer repräsentieren und zwei Label für den Namen und die IP-Adresse besitzen.

Delphi-Quellcode:
type
 TLCComputer = class
  public
   Name, IP: TLabel;
   Column, Row: integer;
 end;
So habe ich den Typ definiert und nun möchte ich gerne eine Instanz davon erzeugen, sodass die Labels auch sichtbar werden.

Mit Computers vom Typ "array of TLCComputers" versuche ich per

Delphi-Quellcode:
 SetLength(Computers, Length(Computers) + 1);

 Computers[Length(Computers)-1].Name := TLabel.Create(self);
 Computers[Length(Computers)-1].Name.Parent := FrmLC;
 Computers[Length(Computers)-1].Name.Left := Column * (cComputerWidth + cComputerSpaceV);
 Computers[Length(Computers)-1].Name.Top := Row *   (cComputerHeight + cComputerSpaceH);

 Computers[Length(Computers)-1].IP := TLabel.Create(self);
 Computers[Length(Computers)-1].IP.Parent := FrmLC;
 Computers[Length(Computers)-1].IP.Left := Column * (cComputerWidth + cComputerSpaceV);
 Computers[Length(Computers)-1].IP.Top := Row *   (cComputerHeight + cComputerSpaceH) + 10;
zur Laufzeit die Label zu erstellen und auf dem Formular "FrmLC" zu erschaffen.

Jedoch erhalte ich beim Start stets nur Zugriffsverletzungen...
Was mache ich falsch?

Schonmal danke für eure Hilfe!

greetZ 64Jabor

jaenicke 6. Mai 2009 17:16

Re: Laufzeitfehler mit eigenem Typ
 
Und wo erstellst du die Klasse? ;-)

// EDIT:
Nebenbei: Wie wäre es mit einer Integervariablen, in der du den Index speicherst? ;-)

64Jabor 6. Mai 2009 17:18

Re: Laufzeitfehler mit eigenem Typ
 
In einer eingebunden Unit

//ja das macht Sinn :D Aber erstmal hat mir das STR+C drücken Spaß gemacht xD

jaenicke 6. Mai 2009 17:19

Re: Laufzeitfehler mit eigenem Typ
 
Zitat:

Zitat von 64Jabor
In einer eingebunden Unit

Warum hast du die entsprechende Zeile dann nicht mit gepostet? :roll:

Ok, wenn die Klasse erstellt ist, dann sollte das soweit korrekt sein.

64Jabor 6. Mai 2009 17:21

Re: Laufzeitfehler mit eigenem Typ
 
Meinst du das

Delphi-Quellcode:
uses MyUnits;
oder die gesamte Unit?
Die Unit wäre:

Delphi-Quellcode:
unit uLC_Computer;

interface

uses
 Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, ComCtrls, ExtCtrls, StdCtrls;

type
 TLCComputer = class
  public
   Name, IP: TLabel;
   Column, Row: integer;
 end;

implementation

end.
Habe zur Sicherheit mal alles eingebunden xD

jaenicke 6. Mai 2009 17:24

Re: Laufzeitfehler mit eigenem Typ
 
Ja, aber irgendwo musst du doch die Klasse TLCComputer in deinem Array erstellen. Den entsprechenden Teil des Quelltextes hast du nicht gepostet oder du machst das gar nicht...
Delphi-Quellcode:
SetLength(Computers, Length(Computers) + 1);
Computers[High(Computers)] := TLCComputer.Create;
Freigeben darfst du am Ende natürlich nicht vergessen, wenn das Programm beendet wird.

Warum nimmst du eigentlich nicht einfach eine TObjectList statt des Arrays? OwnsObjects auf True und du musst dich um die Freigabe nicht mehr kümmern.

jfheins 6. Mai 2009 17:26

Re: Laufzeitfehler mit eigenem Typ
 
Die Klasse sollte die Labels selbst erstellen und nicht public zugänglich machen ;)

Also einen Konstruktor rein und am besten gleich von T(Win)Control ableiten, dann kann die Klasse die Labels auch direkt beinhalten.

So könnte man auch direkte 2 Arrays für die Labels nehmen. Das eigene Control hat noch den Vorteil, dass die Labels zueinander leichter ausgerichtet werden können ;)

himitsu 6. Mai 2009 17:27

Re: Laufzeitfehler mit eigenem Typ
 
er meint wo erstellst du diese Klasseninstanz?

> TLCComputer.Create

Delphi-Quellcode:
SetLength(Computers, Length(Computers) + 1);
Computers[High(Computers)] := TLCComputer.Create;
Computers[High(Computers)].Name := TLabel.Create(self);
...
und vergiß nicht deine Klasse auch wieder mit .Free freizugeben, wenn du sie löschts :!:

PS: warum eine Klasse?
so wie es jetzt ist, reicht ein Record auch aus und der muß nicht erst erstellt werden. :angel2:

64Jabor 6. Mai 2009 17:31

Re: Laufzeitfehler mit eigenem Typ
 
Uhm also ich gebe die "Computers" wieder frei in der OnClose.
Ich definiere das Array aus meiner Klasse in dem private-Teil des Formulares:

Delphi-Quellcode:
private
 { Private-Deklarationen }
 Computers: Array of TLCComputer;
Eine TObjectList? Das werde ich mir mal näher ansehen!

Oh man, ja ich hatte ja gar keine Instanz der Klasse erstellt -.-
Vielen Dank!

Nun ich möchte es recht einfach halten, wäre das dann mit record oder eher mit der ObjectList einfacher?
Ich kenne mich damit noch nicht so aus, ich hab vorher noch nie eine Klasse erstellt :coder:

//edit Wenn ich eine Instaz der Klasse vorher erstelle bleibt der Zugriffsfehler aus, super!

64Jabor 6. Mai 2009 17:50

Re: Laufzeitfehler mit eigenem Typ
 
Also ich habe die Klasse jetzt folgendermaßen abgeändert:

Delphi-Quellcode:
unit uLC_Computer;

interface

uses
 Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, ComCtrls, ExtCtrls, StdCtrls;

const
 cComputerWidth = 100;
 cComputerHeight = 100;
 cComputerSpaceV = 10;
 cComputerSpaceH = 10;

type
 TLCComputer = class(TWinControl)
  private
   Name, IP: TLabel;
   Column, Row: integer;

  public
   constructor Create(NName, NIP: string; Column, Row: integer);
 end;

implementation

constructor TLCComputer.Create(NName, NIP: string; Column, Row: integer);
begin
 Name := TLabel.Create(self);
 Name.Parent := self;
 Name.Caption := NName;
 Name.Left := Column * (cComputerWidth + cComputerSpaceV);
 Name.Top := Row   * (cComputerHeight + cComputerSpaceH);

 IP  := TLabel.Create(self);
 IP.Parent := self;
 IP.Caption := NIP;
 IP.Left  := Column * (cComputerWidth + cComputerSpaceV);
 IP.Top := Row   * (cComputerHeight + cComputerSpaceH) + 10;
end;

end.
Ich erstelle nun einen neuen Computer per

Delphi-Quellcode:
procedure TFrmLC.BtnAddComputerClick(Sender: TObject);
var
 Name, IP: string;
 Column, Row: integer;
begin
 Name := InputBox('Computername', 'Bitte geben Sie einen Computernamen an:', '');
 IP  := InputBox('IP-Adresse', 'Bitte geben Sie die IP-Adresse des Computers an:', '');
 
 SetLength(Computers, Length(Computers) + 1);
 Computers[Length(Computers)-1] := TLCComputer.Create(Name, IP, Column, Row);
end;
Dabei kommen zwar keine Fehler mehr auf, aber die Labels werden nicht sichtbar...
Muss ich die Parent-Eigenschaft der Labels etwa zwingend auf mein Formular setzen?

//edit: Sorry fürs Doppelpost :roll:

DeddyH 6. Mai 2009 17:52

Re: Laufzeitfehler mit eigenem Typ
 
Du könntest einen Owner als Parameter im Konstruktor angeben lassen. Dann könntest Du in demselben auch
Delphi-Quellcode:
inherited Create(Owner);
aufrufen.

[edit] Einen Parent könntest Du dann natürlich auch gleich mit angeben. [/edit]

jaenicke 6. Mai 2009 17:56

Re: Laufzeitfehler mit eigenem Typ
 
Zitat:

Zitat von 64Jabor
Muss ich die Parent-Eigenschaft der Labels etwa zwingend auf mein Formular setzen?

Parent ist das Objekt, auf dem die Komponente angezeigt wird. Wenn du das also nicht richtig setzt, dann kann das auch nicht klappen.

Es wurde ja bereits gesagt, dass es vielleicht sinnvoller wäre z.B. von TWinControl abzuleiten und eine richtige Komponente daraus zu machen. Dann könntest du dir die Label auch gleich sparen und könntest den Text selbst ausgeben...

64Jabor 6. Mai 2009 17:59

Re: Laufzeitfehler mit eigenem Typ
 
Ja ich habe meine Klasse ja von TWinControl abgeleitet!
Dann übergeben ich also nun den Owner und den Parent dem Konstruktor, mal sehen was draus wird :D

jaenicke 6. Mai 2009 18:02

Re: Laufzeitfehler mit eigenem Typ
 
Zitat:

Zitat von 64Jabor
Ja ich habe meine Klasse ja von TWinControl abgeleitet!

:oops: Oops, das habe ich übersehen. Den Owner übergeben reicht aber. Parent auf das WinControl, also Self, setzen ist dann richtig. Dann darf das nicht auf das Formular gesetzt werden.

Kann es sein, dass du die Größe des WinControls oder dessen Parent nirgends setzt?

64Jabor 6. Mai 2009 18:09

Re: Laufzeitfehler mit eigenem Typ
 
Also ich setze die Größe, also Width und Height, meiner Klasse im Konstruktor, das habe ich erst nach meinem Post eingefügt, vorher vergessen!
Die der Label setze ich nicht, in der Hoffnung auf AutoSize :D

Der Owner der Label, also meine Klasse, übergebe ich deren Konstruktoren.
Der Owner meiner Klasse ist das Formular.

Dennoch ist kein Label sichtbar =/

jaenicke 6. Mai 2009 18:11

Re: Laufzeitfehler mit eigenem Typ
 
Und du setzt Parent deines WinControls auf das Formular und das der Labels auf dein WinControl?

64Jabor 6. Mai 2009 18:15

Re: Laufzeitfehler mit eigenem Typ
 
Ja das tue ich, wobei ja Owner und Parent in meinem Fall immer dasselbe Objekt sind, oder nicht?

DeddyH 6. Mai 2009 18:16

Re: Laufzeitfehler mit eigenem Typ
 
Owner und Parent wovon? Der Komponente oder der Labels?

64Jabor 6. Mai 2009 18:18

Re: Laufzeitfehler mit eigenem Typ
 
Naja in beiden Fällen.
Den Owner der Label (meine Klasseninstanz) habe ich ja auch dem Konstruktor der Label übergeben und setze danach deren parent wiederum auf meine Klasseninstanz.
Bei der Klasseninstanz selber verwende ich erst das

Delphi-Quellcode:
inherited Create(Owner);
und setze dann auch wieder den parent auf das Formular...

DeddyH 6. Mai 2009 18:19

Re: Laufzeitfehler mit eigenem Typ
 
Das klingt zumindest richtig.

64Jabor 6. Mai 2009 18:23

Re: Laufzeitfehler mit eigenem Typ
 
:D
Hmm also ich denke ich poste den "gesamten" Code nochmal, eventuell ist im Zusammenhang alles etwas klarer...

Delphi-Quellcode:
constructor TLCComputer.Create(NName, NIP: string; Column, Row: integer; NOwner: TWinControl);
begin
 inherited Create(NOwner);
 Parent := NOwner;

 Width := cComputerWidth;
 Height := cComputerHeight;

 Name := TLabel.Create(self);
 Name.Parent := self;
 Name.Caption := NName;
 Name.Left := Column * (cComputerWidth + cComputerSpaceV);
 Name.Top := Row   * (cComputerHeight + cComputerSpaceH);

 IP  := TLabel.Create(self);
 IP.Parent := self;
 IP.Caption := NIP;
 IP.Left  := Column * (cComputerWidth + cComputerSpaceV);
 IP.Top := Row   * (cComputerHeight + cComputerSpaceH) + 10;
end;
Und die Erstellung der Klasseninstanz:
Delphi-Quellcode:
procedure TFrmLC.BtnAddComputerClick(Sender: TObject);
var
 Name, IP: string;
 Column, Row: integer;
begin
 Name := InputBox('Computername', 'Bitte geben Sie einen Computernamen an:', '');
 IP  := InputBox('IP-Adresse', 'Bitte geben Sie die IP-Adresse des Computers an:', '');

 SetLength(Computers, Length(Computers) + 1);
 Computers[Length(Computers)-1] := TLCComputer.Create(Name, IP, Column, Row, self);
end;
Keine Laufzeitfehler, keine Compilerfehler, läuft einwandfrei nur passieren tut nix ^^

//edit: mir ist bewusst dass durch fehlende Angabe von Column und Row die Left und Top-Werte der label 0 werden, aber das ist ja nicht schlimm

DeddyH 6. Mai 2009 18:31

Re: Laufzeitfehler mit eigenem Typ
 
Und beim Durchsteppen wird auch alles durchlaufen? Hast Du den Konstruktor auch überschrieben?

jfheins 6. Mai 2009 18:35

Re: Laufzeitfehler mit eigenem Typ
 
Ich vermute einfach mal, die Labels sind unsichtbar, weil sie nicht mehr im Ciontrol sind ;)

Du erstellst du Labels und setzt das Parent auf "Self" - das sit gut so, aber die Left und die Top-Eigenschaft des Labels sind nun relativ zur oberen linken Ecke des Parents (= Des neuen Controls)

Proibier mal das so:
Delphi-Quellcode:
constructor TLCComputer.Create(NName, NIP: string; NOwner: TWinControl);
// Column und Row sollten nur in dem Formular eine Rolle spielen
begin
inherited Create(NOwner);
Parent := NOwner;

Width := cComputerWidth; // Sind das globale Variablen?
Height := cComputerHeight;

Name := TLabel.Create(self);
Name.Parent := self;
Name.Caption := NName;
Name.Left := 5;
Name.Top := 5;

IP  := TLabel.Create(self);
IP.Parent := self;
IP.Caption := NIP;
IP.Left  := 5;
IP.Top := 20;
end;
;)

64Jabor 6. Mai 2009 18:38

Re: Laufzeitfehler mit eigenem Typ
 
Ja auch in Einzelschritten wird alles brav durchlaufen.
Den Konstructor überschrieben?

Delphi-Quellcode:
type
 TLCComputer = class(TWinControl)
  private
   Name, IP: TLabel;
   Column, Row: integer;

  public
   constructor Create(NName, NIP: string; Column, Row: integer; NOwner: TWinControl);
 end;
Den Rest kennst du ja...

//edit:
Wenn ich Left und Top explizit angebe, erscheinen die Labels!

Mit Colum und Row wollte ich die Klasseninstanzen später ansprechen, aber das kann ich ja jetzt auch per OnClick auf das TWinControl, nicht?

DeddyH 6. Mai 2009 18:39

Re: Laufzeitfehler mit eigenem Typ
 
Also liegt es an den Koordinaten. Und mit Überschreiben meinte ich das Wörtchen override.

64Jabor 6. Mai 2009 18:43

Re: Laufzeitfehler mit eigenem Typ
 
Nunja es klappt auch ohne...Soll ich trotzdem verwenden?

DeddyH 6. Mai 2009 18:45

Re: Laufzeitfehler mit eigenem Typ
 
Ich würde es tun.

64Jabor 6. Mai 2009 18:49

Re: Laufzeitfehler mit eigenem Typ
 
Okay, aber es funktioniert jetzt alles wunderbar, ich übergebe die Left und Top-Werte der Computerinstanz und positioniere relativ dazu die beiden Labels, und sie werden angezeigt!

Vielen Dank euch allen! :dp:


Alle Zeitangaben in WEZ +1. Es ist jetzt 13:53 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz