Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Sonstige Fragen zu Delphi (https://www.delphipraxis.net/19-sonstige-fragen-zu-delphi/)
-   -   Delphi Problem mit Klassen (https://www.delphipraxis.net/76158-problem-mit-klassen.html)

Cöster 30. Aug 2006 20:17


Problem mit Klassen
 
Hallöle!

Ich hab mir vorgenommen, mein Programm aus mehreren Klassen bestehen zu lassen. Bisher gibt es nur 2 Klassen: Unit1 (die Hauptunit) und Bild.

Da ich zum ersten Mal mit mehreren Klassen arbeite, gibt es auch schon das erste Problem.
Hier erstmal der (noch kurze) Quelltext der Unit Bild:

Delphi-Quellcode:
unit Bild;

interface

uses
  Graphics, Dialogs;

type
  TBild = class
  private
    FCurrentFile: String;
  public
    procedure Oeffnen;
  end;

implementation

uses Unit1;

procedure TBild.Oeffnen;
begin
  If Form1.OpenPictureDialog1.Execute then
  begin
    self.FCurrentFile := Form1.OpenPictureDialog1.FileName;
    Form1.ImMain.Picture.LoadFromFile(Form1.OpenPictureDialog1.FileName);
    Form1.ImMain.Picture.Bitmap.PixelFormat := pf24Bit;
    Form1.ImMain.Visible := True;
  end;
end;
Die Klasse dient also bisher nur dazu, ein Picture zu öffnen und sich seinen Dateinamen zu merken, damit man beim Speichern nicht immer auf "Speichern unter" klicken muss.
Beim Öffnen eines Bitmaps tritt nun eine Zugriffsverletzung auf. Wenn ich die Zeile
Delphi-Quellcode:
self.FCurrentFile := Form1.OpenPictureDialog1.FileName;
weglasse, tritt der Fehler nicht auf.

Kann mir jemand helfen? Falls es eine bessere Möglichkeit gibt, die Dateinamen zu speichern, wäre ich natürlich auch daran interessiert.

Danke!

mkinzler 30. Aug 2006 20:23

Re: Problem mit Klassen
 
Ist Form1 zu diesem Zeitpunkt schon instantiiert?

BTW. ich würde das ganze mal überabeiten, so ist es nämlich nicht so toll!

pszopp 30. Aug 2006 20:54

Re: Problem mit Klassen
 
Hallo Zusammen,

Zitat:

Zitat von mkinzler
Ist Form1 zu diesem Zeitpunkt schon instantiiert?

Ja, denn

Zitat:

Zitat von Cöster
Wenn ich die Zeile
Delphi-Quellcode:
self.FCurrentFile := Form1.OpenPictureDialog1.FileName;
weglasse, tritt der Fehler nicht auf.

wenn die entsprechende Zeile auskommentiert wird, würde der gleiche Fehler in der nächsten Zeile auftreten.
Daher muss Form1 instanziiert sein, da der Fehler ja nicht auftritt :gruebel:

Ich habe eher den Eindruck, das beim Zugriff auf Self ein Fehler entsteht.
Self scheint nil zu sein.

Gruß,
pszopp

GuenterS 30. Aug 2006 20:57

Re: Problem mit Klassen
 
Hast Du denn eine Instanz von TBild erzeugt?

3_of_8 30. Aug 2006 20:59

Re: Problem mit Klassen
 
Wenn self=nil wäre, könnte er nicht mal die Methode aufrufen, da der Methodenzeiger aus einem Pointer auf den Code und einem Pointer auf die Klasseninstanz besteht. Das heißt, wenn die Klasse nicht instantiiert wäre, würde er bevor er in die Methode springt, übelst mit ner AV abschmieren.

Cöster 30. Aug 2006 21:09

Re: Problem mit Klassen
 
Zitat:

Zitat von GuenterS
Hast Du denn eine Instanz von TBild erzeugt?

:lol: Ich Idiot :wall:
Danke, das war's.

Zitat:

Zitat von mkinzler
BTW. ich würde das ganze mal überabeiten, so ist es nämlich nicht so toll!

Danke für den Hinweis. Was schlägst du mir denn vor, wie ich das überarbeiten sollte?

Hawkeye219 30. Aug 2006 21:11

Re: Problem mit Klassen
 
Zitat:

Zitat von 3_of_8
Wenn self=nil wäre, könnte er nicht mal die Methode aufrufen, da der Methodenzeiger aus einem Pointer auf den Code und einem Pointer auf die Klasseninstanz besteht. Das heißt, wenn die Klasse nicht instantiiert wäre, würde er bevor er in die Methode springt, übelst mit ner AV abschmieren.

Diese Aussage stimmt nur für virtuelle Methoden, nicht aber für statische wie die Methode Oeffnen im Beispiel von Cöster. Selbst wenn die Objektreferenz den Wert NIL enthält, wird die Methode aufgerufen. Bei virtuellen Methoden kommt es zu einer Zugriffsverletzung beim Zugriff auf die VMT.

Gruß Hawkeye

mkinzler 30. Aug 2006 21:13

Re: Problem mit Klassen
 
Zitat:

Danke für den Hinweis. Was schlägst du mir denn vor, wie ich das überarbeiten sollte?
Alle Referenzen auf Form1 entfernen, und diese als parameter der Methode übergeben.

3_of_8 30. Aug 2006 21:19

Re: Problem mit Klassen
 
Zitat:

Zitat von Hawkeye219
Zitat:

Zitat von 3_of_8
Wenn self=nil wäre, könnte er nicht mal die Methode aufrufen, da der Methodenzeiger aus einem Pointer auf den Code und einem Pointer auf die Klasseninstanz besteht. Das heißt, wenn die Klasse nicht instantiiert wäre, würde er bevor er in die Methode springt, übelst mit ner AV abschmieren.

Diese Aussage stimmt nur für virtuelle Methoden, nicht aber für statische wie die Methode Oeffnen im Beispiel von Cöster. Selbst wenn die Objektreferenz den Wert NIL enthält, wird die Methode aufgerufen. Bei virtuellen Methoden kommt es zu einer Zugriffsverletzung beim Zugriff auf die VMT.

Gruß Hawkeye

Wieder was dazugelernt. An dieser Stelle könnte man doch eigentlich doch eigentlich Delphi wieder ein bisschen "sicherer" machen, indem man da eine AV raist, oder?

pszopp 30. Aug 2006 21:26

Re: Problem mit Klassen
 
Zitat:

Zitat von 3_of_8
An dieser Stelle könnte man doch eigentlich doch eigentlich Delphi wieder ein bisschen "sicherer" machen, indem man da eine AV raist, oder?

Nein, dann gäbe es ja keine statischen Methoden mehr.

Gruß,
pszopp

Khabarakh 30. Aug 2006 22:14

Re: Problem mit Klassen
 
Zitat:

Zitat von 3_of_8
Wieder was dazugelernt. An dieser Stelle könnte man doch eigentlich doch eigentlich Delphi wieder ein bisschen "sicherer" machen, indem man da eine AV raist, oder?

Dann müsstest du erstmal Free neu implementieren ;) .

3_of_8 30. Aug 2006 22:23

Re: Problem mit Klassen
 
Dafür könnte man ja dann ne Extra-Direktive einführen. :D

Cöster 31. Aug 2006 15:52

Re: Problem mit Klassen
 
Zitat:

Zitat von mkinzler
Zitat:

Danke für den Hinweis. Was schlägst du mir denn vor, wie ich das überarbeiten sollte?
Alle Referenzen auf Form1 entfernen, und diese als parameter der Methode übergeben.

Meinst du so?
Delphi-Quellcode:
procedure TBild.Oeffnen(Dlg: TOpenPictureDialog; Img: TImage);
begin
  If Dlg.Execute then
  begin
    self.FCurrentFile := Dlg.FileName;
    Img.Picture.LoadFromFile(Dlg.FileName);
    Img.Picture.Bitmap.PixelFormat := pf24Bit;
    Img.Visible := True;
  end;
end;

mkinzler 31. Aug 2006 15:58

Re: Problem mit Klassen
 
Ja. Nur hier würde ich auch gleich den Dateiname übergeben:
Delphi-Quellcode:
TBild.Oeffnen(FileName: String; Img: TImage);
...
self.FCurrentFile := FileName;

Cöster 31. Aug 2006 16:04

Re: Problem mit Klassen
 
Zitat:

Zitat von mkinzler
Ja. Nur hier würde ich auch gleich den Dateiname übergeben:
Delphi-Quellcode:
TBild.Oeffnen(FileName: String; Img: TImage);
...
self.FCurrentFile := FileName;

Dann bräuchte ich aber drei Parameter. Für Dlg.Execute brauche ja auch den Parameter des Typs TOpenPictureDialog. Hast du das übersehen?

mkinzler 31. Aug 2006 16:09

Re: Problem mit Klassen
 
Zitat:

Dann bräuchte ich aber drei Parameter. Für Dlg.Execute brauche ja auch den Parameter des Typs TOpenPictureDialog. Hast du das übersehen?
Ja, dann war deine Lösung natürlich besser.

Jelly 31. Aug 2006 16:10

Re: Problem mit Klassen
 
Zitat:

Zitat von Cöster
Dann bräuchte ich aber drei Parameter. Für Dlg.Execute brauche ja auch den Parameter des Typs TOpenPictureDialog. Hast du das übersehen?

Klassen sollen, wenn möglich, für sich alleine werkeln können. Referenzen von anderen Objekten zu übergeben ist also nicht immer angebracht, meiner Meinung nach.

Da ich davon ausgehe, dass Du jetzt kein spezielles TOpenPictureDialog konfigueriert hast, würde ich diesen auch selbst in deiner Klasse erzeugen. Dann brauchst Du nämlich gar nix übergeben... Etwa so:


Delphi-Quellcode:
procedure TBild.Oeffnen(Img: TImage);
var
 dlg : TOpenPictureDialog ;
begin
  try
     Dlg := TOpenPictureDialog.create (Self) ;
     // Hier kannst Du natürlich noch weiter Dlg Eigenschaften einstellen, wie z.B. Dlg.Title oder Dlg.Filter
     If Dlg.Execute then
     begin
       self.FCurrentFile := Dlg.FileName;
       Img.Picture.LoadFromFile(Dlg.FileName);
       Img.Picture.Bitmap.PixelFormat := pf24Bit;
       Img.Visible := True;
     end;
  finally
     Dlg.Free ;
  end ;
end;

Cöster 31. Aug 2006 16:26

Re: Problem mit Klassen
 
Zitat:

Zitat von Jelly
Da ich davon ausgehe, dass Du jetzt kein spezielles TOpenPictureDialog konfigueriert hast...

Was heißt speziell?

Zitat:

Zitat von Jelly
Dlg := TOpenPictureDialog.create (Self) ;

Inkompatible Typen: 'TComponent' und 'TBild'

Noch ne Frage: Wozu ist der try-finally-Block erforderlich. Kann es etwa sein, dass er es nicht schafft den Dialog zu createn?

GuenterS 31. Aug 2006 16:28

Re: Problem mit Klassen
 
Zitat:

Zitat von Jelly
Zitat:

Zitat von Cöster
Dann bräuchte ich aber drei Parameter. Für Dlg.Execute brauche ja auch den Parameter des Typs TOpenPictureDialog. Hast du das übersehen?

Klassen sollen, wenn möglich, für sich alleine werkeln können. Referenzen von anderen Objekten zu übergeben ist also nicht immer angebracht, meiner Meinung nach.

Da ich davon ausgehe, dass Du jetzt kein spezielles TOpenPictureDialog konfigueriert hast, würde ich diesen auch selbst in deiner Klasse erzeugen. Dann brauchst Du nämlich gar nix übergeben... Etwa so:


Delphi-Quellcode:
procedure TBild.Oeffnen(Img: TImage);
var
 dlg : TOpenPictureDialog ;
begin
  try
     Dlg := TOpenPictureDialog.create (Self) ;
     // Hier kannst Du natürlich noch weiter Dlg Eigenschaften einstellen, wie z.B. Dlg.Title oder Dlg.Filter
     If Dlg.Execute then
     begin
       self.FCurrentFile := Dlg.FileName;
       Img.Picture.LoadFromFile(Dlg.FileName);
       Img.Picture.Bitmap.PixelFormat := pf24Bit;
       Img.Visible := True;
     end;
  finally
     Dlg.Free ;
  end ;
end;


Delphi-Quellcode:
procedure TBild.Oeffnen(Img: TImage);
var
 dlg : TOpenPictureDialog ;
begin
     Dlg := TOpenPictureDialog.create (Self) ;
  try
     // Hier kannst Du natürlich noch weiter Dlg Eigenschaften einstellen, wie z.B. Dlg.Title oder Dlg.Filter
     If Dlg.Execute then
     begin
       self.FCurrentFile := Dlg.FileName;
       Img.Picture.LoadFromFile(Dlg.FileName);
       Img.Picture.Bitmap.PixelFormat := pf24Bit;
       Img.Visible := True;
     end;
  finally
     Dlg.Free ;
  end ;
end;
Wäre so besser, da Du sonst versuchst etwas freizugeben, was vielleicht gar nicht erzeugt worden ist, im Falle wenn das Erzeugen des Dialogs schon fehlschlägt.

Jelly 31. Aug 2006 16:32

Re: Problem mit Klassen
 
Zitat:

Zitat von Cöster
Was heißt speziell?

Damit mein die Eigenschaften die du bei deiner TOpenPictureDialog im Object Inspector eingestellt hast. Die müsstest Du dann im Code setzen.

Zitat:

Zitat von Cöster
Inkompatible Typen: 'TComponent' und 'TBild'

Sorry, mein Fehler... TBild ist ja nicht von TComponent abgeleitet... Probier mal
Delphi-Quellcode:
Dlg := TOpenPictureDialog.create (nil) ;
Zitat:

Zitat von Cöster
Noch ne Frage: Wozu ist der try-finally-Block erforderlich. Kann es etwa sein, dass er es nicht schafft den Dialog zu createn?

Es sollte nicht seil können, aber um sicher zu gehen, werden so Create...Free Konstrukte prinzipiell in einen try...finally Block gepackt... Alles unter finally wird auf jeden Fall ausgeführt, auch wenn ein Fehler auftritt. Ist zwar bei deinem bisherigem Code unwahrscheinlich, aber wenn Du den noch um 300 Zeilen ergänzt eventuell nicht mehr.

Jelly 31. Aug 2006 16:33

Re: Problem mit Klassen
 
Zitat:

Zitat von GuenterS
Wäre so besser, da Du sonst versuchst etwas freizugeben, was vielleicht gar nicht erzeugt worden ist, im Falle wenn das Erzeugen des Dialogs schon fehlschlägt.

Richtig :wall:


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