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 property setzen bzw. ändern (https://www.delphipraxis.net/20616-property-setzen-bzw-aendern.html)

cBoB 20. Apr 2004 15:28


property setzen bzw. ändern
 
Hallochen, ich wieder!

Neues Problem:

Unit2:

Delphi-Quellcode:
unit devices;
interface
uses kl2700,Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  Menus, ComCtrls, StdCtrls, ExtCtrls;

type
  TDevice1 = class(TForm)
    FPSheet: TTabSheet;
    procedure SetPSheet(var tst: TTabSheet);
  private
  public
    property PSheet: TTabSheet read FPSheet write SetPSheet;
  end;

implementation
var Dev1 : TDevice1;

procedure TDevice1.SetPSheet(var tst: TTabSheet);
begin
Dev1.FPSheet:=tst;   //hier ist dann vorbei - er wirft ne Fehlermeldung (Exception)
end;
Und dazu aus Unit1, die von Unit2 die probperty PSheet ändern können soll:

Delphi-Quellcode:
var
  Form1: TForm1;
  Dev1: TDevice1;

procedure TForm1.cr_tabs;
const
  TabTitles: array[0..4] of ShortString =
    ('Gerät1','Gerät2','Gerät3','Gerät4','Gerät5');
var
  i: integer;
begin
  for i := 0 to (devcount-1) do
    with TTabSheet.Create(Self) do
    begin
      PageControl := Form1.PageControl1;
      Dev1.PSheet:=PageControl1.Pages[i];      //hier erfolgt der zugriff

      PageControl1.Pages[0].Show;
   end;
end;
Nun stürtzt das Programm aber immer ab, wenn ich auf PSheet zugreifen will. Durch den Einzelschrittbetrieb kann ich sehen, daß es erst bei der direkten Zuweisung anhält.
Was kann falsch sein?
-c-

maximov 20. Apr 2004 15:32

Re: property setzen bzw. ändern
 
Hi.

Du missbrauchst properties, die zum kapseln von lokalen objekt-feldern da sind, und nicht um an globalen rum zu manipulieren :wink:

Teste es mal so:
Delphi-Quellcode:
procedure TDevice1.SetPSheet(var tst: TTabSheet);
begin
  self.FPSheet:=tst;   //hier ist dann vorbei - er wirft ne Fehlermeldung (Exception)
end;

Muetze1 20. Apr 2004 15:38

Re: property setzen bzw. ändern
 
Moin!

Das Self braucht nicht geschrieben werden in diesem Falle, ansonsten sind noch 2 Dinge auffällig:

1. Du hast in deinem Code in jeder der beiden Units die Variabel Dev1 : TDevice1 definiert - aber nun ist die Frage, wird überhaupt eine - und wenn, welche - mit einer Instanz von TDevice1 gefüllt?

2. Dein FPSheet ist schon Public definiert, somit frei von aussen zugreifbar - also, wozu die Properties? (siehe maximov).

MfG
Muetze1

cBoB 20. Apr 2004 16:28

Re: property setzen bzw. ändern
 
Momomomoment - nicht ganz so hastig! Wie gesagt, ich bin noch nicht lange dabei, Delphi zu programmieren. So die Standardsachen wie einfache Dateioperationen oder Statische Formulare usw. benötigen ja nicht so das Hintergrundwissen - die funktionieren halt einfach, wenn man sich da was zusammenklickt. Aber wenns dann um dynamische oder gar eben selbst erstellete Objekte geht, dann wirds schon schlimm - aber irgendwie muß man ja mal anfangen und daran kommen, nich?

So, und nun wieder zurück zum Thema!
Wie meinste das genau mit instanziieren? Meinst Du, es müßte eine Instanz mittels Dev1.Create erzeugt werden? Nein, das kommt in beiden Units nicht vor. Bis jetzt kam ich aber an die anderen (hier zwar nicht zu sehen) Methoden heran, die noch damit verbunden sind. Und daß in beiden Units Dev1 defieniert wurde, dürfte doch auch nicht stören, da diese doch eigentlich nur für eine Unit als global zu sehen sind, oder?
Und zum 2. Punkt: Ich wollte FPSheet ja auch schon direkt ansprechen, aber war das Programm auch der Meinung, daß das eine Zugriffsverletzung sei...
Also weitersuchen und MEHR INPUT :shock:

-c-


PS: Wer kann ne gut Buchempfehlung aussprechen?! Aber nicht unbedingt so ein Buch, dass erst erklärt, was der Unterschied zwischen nem Interpreter und nem Kompiler ist. :stupid:

Muetze1 20. Apr 2004 21:05

Re: property setzen bzw. ändern
 
Moin!

Du hast in beiden Units

Code:
Var
  Dev1 : TDevice1;
stehen. Dieses beides enthält nur einen Platzhalter wo du nachher eine Instanz von TDevice1 reinlegen kannst. Standardmässig gibt es sowas aber nicht in den Variablen, daher bekommst du bei dem Zugriff auf Dev1.xxx auch Probleme - da ist noch nix. Um da aber was reinzubekommen gibt es die Möglichkeit das Objekt anzulegen (instanziieren), und ja, es geht so wie du meintest (fast)

Code:
  Dev1 := TDevice1.Create();
Die Frage ist dabei nur noch, welche Parameter du beim Create mit angeben musst, und in welchem Dev1 du das abspeicherst. Dadurch das du es in beiden Units deklaraiert hast, kann es leicht zu Verwechselungen kommen so dass du auf die falsche Variable zugreifst. Und du greifst ja auf Dev1 in deinem Code zu - und wenn da noch keine Instanz drinne ist in Dev1, dann kommt es zu der Zugriffsverletzung.

Ich bin noch nicht so lange hier (ein paar Tage), daher die Frage an die anderen: gibt es hier ein Tutorial für OOP ?

MfG
Muetze1

cBoB 21. Apr 2004 07:36

Re: property setzen bzw. ändern
 
Morgen Muetze!
Prinzipiell ist mir das mit OOP schon klar, schwer ist es eben, durch die ganzen Konventionen durchzublicken. Die Idee mit dem Tut und dann eben schön auf Delphi bezogen ist nicht schlecht, aber ich glaub, ich hab hier davon schon was gesehen. Aber bin auch noch nicht länger als Du dabei.

Nochmal zurück zum Thema: warum kann ich aber dann trotzdem auf die Methoden aus TDevice1 zurückgreifen, auch wenns noch nicht instanziiert ist?

-c-

oki 21. Apr 2004 09:00

Re: property setzen bzw. ändern
 
Hi CBOB,

schau mal in deinen Project-Code. Offensichtlich hast du dein Formular aus Unit2 deinem Projekt hinzugefügt. Somit wird automatisch schon eine Instanz beim Prog-Start erzeugt. Nun kann ich natürlich nicht sagen, was du an dem vorliegenden Code alles geändert hast.

Die übliche Vorgehensweise ist aber so:

1. Du fügst ein neues Formular in dein Projekt ein, und Delphi erzeugt automatisch den Aufruf
Delphi-Quellcode:
  Application.CreateForm(TForm1, Device1);
Somit besteht eine Instanze die genutzt werden kann. Üblicheweise erzeugt Delphi auch automatisch die Instanz-Variable im implementation-Teil deiner Formular-Unit (hier Unit2)

2. Du machst das lieber alles alleine:

hier wähle ich folgende Verfahrensweise. Zum Bsp. im Main-Form creiere ich das Formular im OnCreate Ereignes meines MainForm. Das dann, wenn es für die ganze Laufzeit erhalten bleiben soll. Dann muß aber beachtet werden, dass bei Aufrufen aus anderen Units die Instanz global verfügbar sein muß. Das hat oben Delphi aber automatisch für mich gemacht. Sinn bringt das eigentlich nur, für spezielle Nutzungen, bei denen Du das entsprechende Formular oder Objekt in einer Instanz unbedingt privat kapseln möchtest.

Nun gut, was machst du im eigentlichen Object:

Hier solltest du eigentlich nie globale Bezüge verwenden, da damit dein Object unflexibel wird. Es ist immer an speziell erstellte instanzen gebunden etc.

In deinem eigenen Object kannst du der Einfachheit halber immer direkt auf eigene Eigenschaften und Methoden ohne Instanzangabe zugreifen. Der Parameter self wird sozusagen implizit unterstellt.

Bsp.:
Delphi-Quellcode:
procedure TDevice1.SetPSheet(var tst: TTabSheet);
begin
  FPSheet:=tst;  
end;


// entspricht:
procedure TDevice1.SetPSheet(var tst: TTabSheet);
begin
  self.FPSheet:=tst;  
end;
Deine Unit 2 sollte in der eigenen Erstellung eigentlich so aussehen:

Delphi-Quellcode:
unit devices;
interface
uses kl2700,Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  Menus, ComCtrls, StdCtrls, ExtCtrls;

type
  TDevice1 = class(TForm)
  private
    FPSheet: TTabSheet;
    procedure SetPSheet(var tst: TTabSheet);
  public
    property PSheet: TTabSheet read FPSheet write SetPSheet;
  end;

var Dev1 : TDevice1;

implementation

procedure TDevice1.SetPSheet(var tst: TTabSheet);
begin
  FPSheet:=tst;   //hier ist dann vorbei - er wirft ne Fehlermeldung (Exception)
end;
Passiert das alles nicht per Drag and Drop im Fomular kümmerst Du dich selber um das Creieren Deiner Objekte.

Machst du es per Drag and Drop, sind diese Public und ein Property tut wirklich nicht not.

Gut, ich hoffe es war verständlich,

Gruß oki

maximov 21. Apr 2004 09:08

Re: property setzen bzw. ändern
 
Zitat:

Zitat von cBoB
...

Nochmal zurück zum Thema: warum kann ich aber dann trotzdem auf die Methoden aus TDevice1 zurückgreifen, auch wenns noch nicht instanziiert ist?

Du kannst (zur laufzeit) nur solange auf methoden, von objekten die noch nicht instanziert sind (nil), zugreiffen, wie dort nicht mit den objekt-daten gearbeitet wird! Denn dann wird faktisch nicht auf den objekt-speicher zugegriffen, nur auf den code der klasse.

Und (besser man sagt es dir früher als spät) man sollte soweit wie möglich auf globale variablen verzichten, weil das schlechten stil fördert.

oki 21. Apr 2004 09:14

Re: property setzen bzw. ändern
 
[quote="maximov"]
Zitat:

Zitat von cBoB
...

Und (besser man sagt es dir früher als spät) man sollte soweit wie möglich auf globale variablen verzichten, weil das schlechten stil fördert.

dem schließe ich mich uneingeschränkt an!

Gruß oki

cBoB 21. Apr 2004 09:19

Re: property setzen bzw. ändern
 
@oki
Danke für die Ausführlichkeit! Hab das aber schon so irgendwie hingebogen bekommen - quasi übernacht :wink: .

@max
Aha, hab mir sowas in der Art schon gedacht. Was meinst Du hier aber genau mit Objectdaten?
Und daß Globale Variablen vermieden werden sollten, war mir auch schon klar. Ich bemüh mich jedenfalls, wenig davon gebrauch zu machen. In einigen wenigen Fällen kommt man aber drum rum.

Was ist eigentlich mit ner Buchempfehlung zum Thema? Woher habt Ihr Eure Erfahrung bzw. Wissen - zugeflogen kommt sowas bis jetzt ja noch nicht, oder? :angle:

-c-

Muetze1 21. Apr 2004 09:40

Re: property setzen bzw. ändern
 
Moin!

Zitat:

Zitat von maximov
Du kannst (zur laufzeit) nur solange auf methoden, von objekten die noch nicht instanziert sind (nil), zugreiffen, wie dort nicht mit den objekt-daten gearbeitet wird! Denn dann wird faktisch nicht auf den objekt-speicher zugegriffen, nur auf den code der klasse.

Nicht ganz richtig: Der Zugriff auf nicht statische Klassenmethoden ist bei einer Instanzenvariable von Nil nicht möglich, da der Compiler automatisch Code für den Zugriff auf die VMT erzeugt um die Adresse der Methode zu ermitteln. Somit wäre die Methodenadresse um dorthin zu springen an der Stelle hinterlegt (Instanz + VMT Eintragsoffset) z.B. NIL+$08 - was aber dann eine EAccessViolation bei $000008 erzeugt, wenn er die Adresse holen will.
Das geht nur mit statischen Funktionen (das ist der Name in C++, Delphi nennt das Class Procedure/Function).

----

Ich vermute immernoch, das du die ganze Zeit auf Dev1 aus der Unit zugegriffen hast, die Nil ist und in Unit2 wo die Instanz in der Dev1 vorhanden war auf die Methoden...

MfG
Muetze1

cBoB 21. Apr 2004 10:55

Re: property setzen bzw. ändern
 
@Muetze
Hab jetzt ordnungsgemäß in Unit1 eine Instanz von Dev1 erzeugt und in Unit2 die Definition von Dev1 entfernt. Und was soll ich sagen: Isch hoab doa uff'n Knobb gedrüggt und der gääht! :thuimb:

Nächste kleine Frage am Rande: Wenn ich nun innerhalb von Unit2 eine ComboBox erzeugt hab und dann das OnChange Event auf eine weiter procedure 'CBChange' innerhalb von Unit2 gelenkt hab, kann ich doch nur von außen darauf zugreifen, wenn ich CBChange als public und als virtual definiere und dann innerhalb von Unit1 diese procedure dann überschreibe, oder? Zumindest wäre es ein Weg, weils halt funktioniert. Gäbe es aber auch andere Möglichkeiten?

Und 2. Frage ist: Wenn ich nun die in Unit2 erzeugte ComboBox nehme und dann per Parent in das Form1 aus Unit1 hänge, wie kann ich dann auf das Ding ordnungsgemäß zugreifen? Ich habs mittels ewig langer Schlange:
Delphi-Quellcode:
with Form1.PageControl1.ActivePage.Controls[0] as TComboBox do
rrealisiert, was mir aber nicht so gefällt, weil es dann ja immer an einer bestimmten Stelle in der Hirarchie erwartet wird. Und über einen Namen kann ich da ja auch nicht zugreifen, den weiß ja Form1 auch nicht.

Uiih, doch wieder so lang geworden :oops:

Gruß
-c-

maximov 21. Apr 2004 11:24

Re: property setzen bzw. ändern
 
Zitat:

Zitat von Muetze1
...
Nicht ganz richtig: Der Zugriff auf nicht statische Klassenmethoden ist bei einer Instanzenvariable von Nil nicht möglich, da der Compiler automatisch Code für den Zugriff auf die VMT erzeugt um die Adresse der Methode zu ermitteln. Somit wäre die Methodenadresse um dorthin zu springen an der Stelle hinterlegt (Instanz + VMT Eintragsoffset) z.B. NIL+$08 - was aber dann eine EAccessViolation bei $000008 erzeugt, wenn er die Adresse holen will.
Das geht nur mit statischen Funktionen (das ist der Name in C++, Delphi nennt das Class Procedure/Function).
...

Leider muss ich dich enttäuschen :mrgreen: Du gehst davon aus, dass die methoden vom object-pointer aussgehend addressiert werden (nil+&80), das würde nur sinn machen wenn jedes object sich eine kopie der methoden einer klasse anlegt. Dem ist nicht so! Sondern die methode werden vom klassen-pointer ausgehend addressiert und der objekt-pointer wird als unsichtbarer self-parameter übergeben. Deshalt funktioniert dies auch, da ich nicht auf objekt-felder zugreife:

Delphi-Quellcode:
type
  TTest = class
    procedure NoStatic(str:string);
  end;      

{ TTest }

procedure TTest.NoStatic(str: string);
begin
  ShowMessage(str);
end;

procedure TForm1.Button1Click(Sender: TObject);
var x:TTest;
begin
  x.NoStatic('No Exception');
end;
zB. unser schöne free würde sonst auch keinen sinn machen :wink:

Muetze1 21. Apr 2004 13:14

Re: property setzen bzw. ändern
 
Moin!

maximov, du hast Recht. Ich habe beim vorherigen Post das nicht beachtet, das die VMT ja von der Klasse kommt und nicht bei der Instanz steht. Ich nehme alles zurück und behaupte das Gegenteil.

MfG
Muetze1

cBoB 21. Apr 2004 13:30

Re: property setzen bzw. ändern
 
Hey, und mit mir redet keiner mehr?
Nerv' ich mittlerweile schon so mit meinen Fragen?

-c-

maximov 21. Apr 2004 14:02

Re: property setzen bzw. ändern
 
Das musste eben geklärt werden :wink:

Zitat:

Zitat von cBoB
...
Nächste kleine Frage am Rande: Wenn ich nun innerhalb von Unit2 eine ComboBox erzeugt hab und dann das OnChange Event auf eine weiter procedure 'CBChange' innerhalb von Unit2 gelenkt hab, kann ich doch nur von außen darauf zugreifen, wenn ich CBChange als public und als virtual definiere und dann innerhalb von Unit1 diese procedure dann überschreibe, oder? Zumindest wäre es ein Weg, weils halt funktioniert. Gäbe es aber auch andere Möglichkeiten?

Hast du die klasse in unit1 von der in unit2 (oder umgekehrt [hab den überblick verloren]) abgeleitet? wenn nein dann muss da nix virtuell oder overrided werden, sondern kannst einfach per code die methode dem event zuweisen.
Zitat:

Und 2. Frage ist: Wenn ich nun die in Unit2 erzeugte ComboBox nehme und dann per Parent in das Form1 aus Unit1 hänge, wie kann ich dann auf das Ding ordnungsgemäß zugreifen? Ich habs mittels ewig langer Schlange:
Delphi-Quellcode:
with Form1.PageControl1.ActivePage.Controls[0] as TComboBox do
rrealisiert, was mir aber nicht so gefällt, weil es dann ja immer an einer bestimmten Stelle in der Hirarchie erwartet wird. Und über einen Namen kann ich da ja auch nicht zugreifen, den weiß ja Form1 auch nicht.
...
zeig mal mehr code und sag nochmal, in klaren worten, was in dem event passieren soll!

Muetze1 21. Apr 2004 14:08

Re: property setzen bzw. ändern
 
Moin!

Du? Ach du, ja, da war doch noch was...

Zitat:

Zitat von cBoB
Nächste kleine Frage am Rande: Wenn ich nun innerhalb von Unit2 eine ComboBox erzeugt hab und dann das OnChange Event auf eine weiter procedure 'CBChange' innerhalb von Unit2 gelenkt hab, kann ich doch nur von außen darauf zugreifen, wenn ich CBChange als public und als virtual definiere und dann innerhalb von Unit1 diese procedure dann überschreibe, oder? Zumindest wäre es ein Weg, weils halt funktioniert. Gäbe es aber auch andere Möglichkeiten?

Kein Wort verstanden - selbst nach dem 3. Lesen nicht...

Zitat:

Zitat von cBoB
Und 2. Frage ist: Wenn ich nun die in Unit2 erzeugte ComboBox nehme und dann per Parent in das Form1 aus Unit1 hänge, wie kann ich dann auf das Ding ordnungsgemäß zugreifen? Ich habs mittels ewig langer Schlange:

Merk dir doch einfach die angelegte Instanz in einer Variablen (ähnlich wie das Dev1 für die TDevice1 Instanz) beim Create und greif dann über die Variable zu...

Bsp:
Delphi-Quellcode:
Type
  TFormX = Class(TForm)
  dein vorhandener Form Code
  Private
    ComboBox_Neu : TComboBox;
  ...
Und wo du das Create machst, dann sowas:

Delphi-Quellcode:
  ComboBox_Neu := TComboBox.Create( ... wie gehabt ... );
  ComboBox_Neu.Text := 'wasweissich';
Und im Code kannst du dann wie im letzten Teil geschrieben mit ComboBox_Neu. auf die Eigenschaften der ComboBox zugreifen. In den Events/Ereignissen die von der ComboBox ausgelöst werden, entspricht der Sender immer der ComboBox...

MfG
Muetze1


Alle Zeitangaben in WEZ +1. Es ist jetzt 09:33 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