![]() |
Re: Bitmap zurück geben und freigeben
Junge, watt machst du denn da...
Du legst ein Bitmap an, gibst es an die Funktion Appear(), wo du erneut ein Bitmap anlegst. Dann trittst du das übergebene Bitmap mit den Füßen und weist das lokale zu. Also: Wir hatten doch extra vorgeschlagen das Bitmap zu übergeben, damit du in der Funktion nichts mehr anlegen oder freigeben musst - weil halt genau dieses alles nach außen gelegt wurde...
Delphi-Quellcode:
function TStaticObject.Appear( const Dest: TBitmap ) : TBitMap;
begin // nicht unwichtig, sondern alles auf Dest machen! end; |
Re: Bitmap zurück geben und freigeben
jawohl ich habe verstanden
Thx Edit: Es geht aber trozdem erhalte ich die meldung das mit die ressoucen ausgehen |
Re: Bitmap zurück geben und freigeben
Also, wenn ich davon ausgehe, dass die bisher besprochene Funktion nun so wie geraten ist, dann solltest du ein anderes Leck an einer anderen Stelle haben...
|
Re: Bitmap zurück geben und freigeben
Zitat:
Delphi-Quellcode:
Der Rückgabewert hat sich somit erledigt, oder mache ich jetzt einen Denkfehler?
procedure TStaticObject.Appear( const Dest: TBitmap );
|
Re: Bitmap zurück geben und freigeben
Mal ganz blöd gefragt. Warum musst du eigentlich jedes Mal ein Bild anlegen, wenn du das Objekt zeichnen willst? Wäre es nicht besser, wenn das StaticObjekt sich selbst um die Verwaltung des Bitmaps kümmert und es nur zur Verfügung stellt. Also mit anderen Worten beim Erstellen des StaticObject wird das Bitmap angelegt und evtl schon befüllt und beim Zeichnen greifst du nur noch auf dieses erstellte Bitmap zu.
Wenn das Bitmap sehr dynamisch sein muss, dann kannst es aber auch trotzdem so lösen. Aber in dem Appear dann einfach nur das interne Bitmap befüllen, zurückgeben und nur benutzen. Also nicht freigeben. Um es etwas zu verdeutlichen.
Delphi-Quellcode:
Darstellen könntest du es dann folgendermaßen.
type
TStaticObject = class private fBitmap: TBitmap; public property Bitmap: Integer read fBitmap; function Appear: TBitmap; constructor Create; destructor Destroy; override; end; constructor TStaticObject.Create; begin inherited; fBitmap := TBitmap.Create; // Entweder hier schon befüllen. end; destructor TStaticObject.Destroy; begin fBitmap.Free; inherited; end; function TStaticObject.Appear: TBitmap; begin // Oder hier das Bitmap befüllen und zurückgeben Result := fBitmap; end;
Delphi-Quellcode:
Damit könntest du bei jedem Zeichnen das Bitmap anpassen (Methode Appear), falls das StaticObject doch mehr ein dynamisches Objekt ist. Du würdest aber a. nicht ständig bitmaps anlegen und freigeben und b. hättest auch kein Speicherloch und c. einfacher code und klare regelung wer sich um das Bitmap zu kümmern hat. Nämlich die Klasse TStaticObject zu der es ja schließlich gehört und niemand anders.
// entweder direkt das Bitmap darstellen
GameScreen.Canvas.Draw(StaticObject.PosX, StaticObject.PosY, StaticObject.Bitmap); // oder aber mit der Methode die nur das Bitmap zurück gibt. GameScreen.Canvas.Draw(StaticObject.PosX, StaticObject.PosY, StaticObject.Appear); PS: Es ist übrigens nicht so abwägig, dass sich die Objekte selber zeichnen. Denn eigentlich ist das genau der tiefere Sinn hinter OOP. Die Szene muss so immer genau wissen wie die Objekte gezeichnet werden müssen. Und das gehört eigentlich nicht zu ihren Aufgaben. Besser (klarrer Strukturiert) wäre es, wenn nur das Objekt wüsste wie es gezeichnet werden muss und sich auch selbst darum kümmert. Die Szene würde dann nur sagen. ObjektXYZ zeichne dich mal. Das aber nur so am Rande. ;) |
Re: Bitmap zurück geben und freigeben
Also das Problem ist allerdings, dass das BitMap immer anders aussehen kann und man auch noch die Farben verstellen kann...
Ich zeige euch einfach mal die gesamte Klasse:
Delphi-Quellcode:
Das Problem an deinem Vorschlag ist, dass das Bild extrem dynamisch ist und sich in jedem Frame verändern kann. Ob größe oder Farbe und Tranzparentz... Sonst wäre das ja ganz einfach.
type
TStaticObjectMouseEvent = procedure(X:integer;Y:integer; //MousePosition on the Object ScreenX:integer;ScreenY:integer); //MousePosition on the Screen TStaticObject = class(TObject) private { Grafik } Graphic : TBitMap; //Eine einfache BitMap { Events } FOnClick : TStaticObjectMouseEvent; //When the User klicks on the Object FOnMouseOver : TStaticObjectMouseEvent; //When the mouse goes over the Object FOnMouseOut : TStaticObjectMouseEvent; //When the mouse goes out the Object public { Position & Größe , Read + Write } PosX : integer; PosY : integer; Width : integer; Height: integer; ZIndex: integer; { Farben } Colors : TRGBColorList; { Boolische Ausdrücke, Read + Write } AutoSize: boolean; //Ändert die Breite und Höhe automatisch auf orginal, ansonsten wir aus Width & Height zugeschnitten Visible : boolean; //Ist das Objekt sichbar oder nicht, wird von T2DScreen geprüft //Appear gibt ein leerBmp zurück { Sonstige Eigenschaften } TranzparentColor: TColor; Tranzparent : boolean; { Eigenschaften der Events } property OnClick : TStaticObjectMouseEvent read FOnClick write FOnClick; property OnMouseOver : TStaticObjectMouseEvent read FOnMouseOver write FOnMouseOver; property OnMouseOut : TStaticObjectMouseEvent read FOnMouseOut write FOnMouseOut; { TODO 3 : Die Funktionen für den Aufruf der Methode müssen noch geschrieben werden } { Bild } property Image : TBitMap read Graphic; { Constructor } constructor Create(FilePath: PAnsiChar;Visibility : boolean = false); destructor Destroy; { Proceduren } function ChangeGraphic(FilePath : PAnsiChar) : boolean; function Appear( const Dest: TBitmap ): TBitMap; end; implementation constructor TStaticObject.Create(FilePath: PAnsiChar; Visibility : boolean = false); begin //Prüfen wir ob di Datei existiert if fileexists(FilePath) then begin try //Fehlern vorbeugen //Grafik laden ChangeGraphic(FilePath); //Boolische Tüpen setzen AutoSize := true; Visible := Visibility; //Colors Colors.Red := 255; Colors.Green := 255; Colors.Blue := 255; Colors.Alpha := 255; except //Selbst löschen self.Free; end; end; end; function TStaticObject.ChangeGraphic(FilePath: PAnsiChar) : boolean; begin if fileexists(FilePath) then begin try //Fehlern vorbeugen //Prüfen ob Graphic eine Instanz ist if Assigned(Graphic) then Graphic.FreeImage; //Graphic TBitMap erstellen Graphic := TBitMap.Create; //BitMap laden Graphic.LoadFromFile(FilePath); //Rückgabe Result := true; except Result := false; end; end; end; destructor TStaticObject.Destroy; begin try //Graphic freigeben Graphic.FreeImage; finally self.Free; //Selber freigeben end; end; function TStaticObject.Appear( const Dest: TBitmap ) : TBitMap; begin try //Autosize if Autosize and Visible then begin Width := Graphic.Width; Height := Graphic.Height; end else if not Visible then begin Width := 0; Height := 0; end; //Imagegröße Dest.Width := Width; Dest.Height := Height; { DONE 1 : Die Eigenschaft Visible muss noch berücksichtigt werden } if Visible then begin //Kopiern und ggf. skalieren Dest.Canvas.StretchDraw(bounds(0,0,Width,Height),Graphic); //Bildtranzparents Dest.Transparent := Tranzparent; Dest.TransparentColor := TranzparentColor; Dest.TransparentMode := tmFixed; //Prüfen ob die Farberwerte geändert wurden if ( Colors.Red <> 255 ) or ( Colors.Green <> 255 ) or ( Colors.Blue <> 255 ) then FilterColors(Colors,Dest); end; finally //Nichts end; end; Und unter einem statischen Objekt verstehe ich ein Objekt das nicht animiert ist, also was aus keinem FarmeSet besteht. Man kann zwar in jedem Frame das Bild wechseln, jedoh ist dafür das TAnimatedObject besser geeignet... 8) Das Problem beim selber zeichnen ist, dass der Bildschrim auch events wie OnClick und OnMouseOver/Out bearbeiten muss... |
Re: Bitmap zurück geben und freigeben
Zum Thema ändern: Ja wo ist da jetzt das Problem? Es geht mir ja nur darum, dass das Objekt sein Bitmap selber verwaltet und es außerhalb deines Objektes nur benutzt wird. Was und wann dieses Objekt mit dem Bitmap macht ist ihm überlassen. Beim Zeichnen kannst du ja trotzdem eine Funktion aufrufen die das interne Bitmap aktualisiert und diesen dann zurückgibt.
Da du bei dir das Bild noch in der Größe verändern möchtest benötigst du also 2 Bitmaps. Ein Mal das Originale und ein Mal das zu zeichnende Bild. Wobei es wohl besser wäre, wenn du das originale Bild gestreckt direkt auf das Canvas zeichnen würdest. Denn das würde zeichnerrei und Speicher sparen. Evtl wäre es langsamer als wie wenn man das zu zeichnende Bild zwischenspeichert aber da du das in deinem Code ja auch jedes mal neu erstellst wird es zu mindest nicht langsamer als der bestehende Code. Hier noch ein paar Hinweise zu deinem Code: Im Destruktor nicht Self.Free aufrufen sondern IMMER Inherited und die Methode auch IMMER überschreiben. Also override benutzen. Außer es hat einen sehr triftigen Grund. Und den sehe ich bei dir nicht. ;) Solltest du Destroy überschreiben und self.free aufrufen endet das in einer Endlosschleife. Wenn ich mich nicht vertue. Ein Self.Free im Falle eines Fehlers innerhalb Konstruktors. Das kannst du dir sparen, denn sobald im Konstruktor ein Fehler auftritt der diesen beenden würde, wird die Instanz wieder freigegeben. Außerdem wird die Exception weiter gereicht. In deinem Falle würde die Exception unterdrückt werden aber die Instanz würde wieder freigegeben werden. Was evtl sogar fatal wäre, da es sogar so sein müsste/könnte, dass TStaticObject.Create einen Pointer zurück liefern müsste. Aber einen Pointer auf ein Objekt welches schon wieder freigegeben wurde. Du kannst als Später nicht mehr entscheiden ob es richtig ist oder nicht. Graphic.FreeImage: Freeimage löscht nicht die Instanz sondern lediglich die Bilddaten. Die Instanz existiert also weiterhin. Das verringert zwar das Speicherloch erheblich. Aber es ist trotzdem eines da. Auch wenn es ein bisschen Offtopic wird. ;) TAnimatedObject und TStaticObject sollten einen gemeinsamen Vorfahren haben. Beide von TObject abzuleiten ist kein schöner OOP Stil. Denn genau genommen unterscheiden sie sich "lediglich" dadurch, dass das TAnimatedObject eine Animation hat. Ansonsten sind es beide irgendwelche Dinger die gezeichnet werden. Und falls doch noch mehr Unterschiede existieren, dann kann man auch noch eine Ableitung dazwischen setzen. Zum Thema OnClick. Ich weiß nicht was du da so machst aber eigentlich ist so etwas eben auch prädestiniert für OOP. Ich habe solche Konstruktionen schon ein paar mal gemacht und hat bisher immer geklappt. Evtl solltest du mal andenken in einem anderen Thema mal nach Designvorschlägen/Ideen/Anregungen fragen. So etwas macht im Endeffeckt dann auch deine Arbeit leichter. Speziell wenn es noch komplizierter wird. Ist aber nur eine Idee. |
Re: Bitmap zurück geben und freigeben
OKay danke für die Tipps, allerdings habe ich manches noch net so wirklich verstanden.. :roteyes:
Also das mit dem try...except self.free kann ich im constructor weg lassen, da die exception zurück gegeben wird. Dann habe ich das nicht so verstanden was ich jetzt mit dem Destructor machen soll, also mit override überschreiben und dann? Was ist jetzt mit dem Inherited Free? Sonst geht alles Thx Edit: die tranzparents geht aus irgendeinem grund verlohren bei übergabe in das TempBMP? Edit2: Hihi okay die Tranzparents is auch wieder da^^ |
Re: Bitmap zurück geben und freigeben
Den Destruktor wie in
![]() Zur Erklärung. Der Destruktor ist virtuell. Deswegen muss man den Überschreiben, da sonst die Methode nur verdeckt wird. Und inherited dient dazu um eine Methode aus der Vorfahrenklasse aufzurufen. Damit auch andere Destruktoren aufgerufen werden. Free ruft intern auch nur Destroy auf. Plus eine Sicherheitsabfrage. Falls zu Klasse noch Lücken sind würde ich aber eher zu ![]() |
Re: Bitmap zurück geben und freigeben
Zitat:
|
Alle Zeitangaben in WEZ +1. Es ist jetzt 13:53 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