AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Programmierung allgemein Multimedia Bitmap soll gelegentlich unsichtbar sein
Thema durchsuchen
Ansicht
Themen-Optionen

Bitmap soll gelegentlich unsichtbar sein

Ein Thema von Popov · begonnen am 21. Jan 2014 · letzter Beitrag vom 2. Feb 2014
Antwort Antwort
Benutzerbild von DeddyH
DeddyH

Registriert seit: 17. Sep 2006
Ort: Barchfeld
27.666 Beiträge
 
Delphi 12 Athens
 
#1

AW: Bitmap soll gelegentlich unsichtbar sein

  Alt 31. Jan 2014, 14:26
Du hast in Deinem Code ein potentielles Speicherleck und eine potentielle AV. Wenn der Bitmap-Eigenschaft eine andere Bitmap zugewiesen wird, ändert sich der Instanzzeiger von der selbst erstellten auf die zugewiesene, somit kann die selbst erstellte nicht mehr freigegeben werden, stattdessen zieht man beim Zerstören der Klasse womöglich anderen Klassen die Bitmap unter dem Hintern weg. Du kannst das mit einem Setter, innerhalb dessen Du einfach die übergebene Instanz in Deine eigene kopierst (Assign), vermeiden. Somit hast Du dann weiterhin getrennte Instanzen, aber mit gleichen Eigenschaften.
Detlef
"Ich habe Angst vor dem Tag, an dem die Technologie unsere menschlichen Interaktionen übertrumpft. Die Welt wird eine Generation von Idioten bekommen." (Albert Einstein)
Dieser Tag ist längst gekommen
  Mit Zitat antworten Zitat
Popov
(Gast)

n/a Beiträge
 
#2

AW: Bitmap soll gelegentlich unsichtbar sein

  Alt 31. Jan 2014, 16:45
Danke für den Hinweis, aber wie gesagt, es ist nur eine Machbarkeitsstudie gewesen, ein Test, oder wie man das sonst nennt.

Trotzdem, wo siehst du die potentielle Gefahr genau? Ich denke du erkennst die Gefahr dort wo ich sie schon im ersten Post gesehen habe: "Das würde die Aufgabe erfüllen, aber die Objektadresse würde nicht stimmen. Könnte zu Problemen führen wenn einer die nutzen würde."

Das ist eigentlich auch der Grund wieso ich es nicht so machen wollte und nach Ideen suchte. Wobei ich das gleiche auch in Blau (nicht in Grün) versucht hatte, also statt einer Backup-Bitmap das Bild in MemoryStream sichern.
  Mit Zitat antworten Zitat
Benutzerbild von DeddyH
DeddyH

Registriert seit: 17. Sep 2006
Ort: Barchfeld
27.666 Beiträge
 
Delphi 12 Athens
 
#3

AW: Bitmap soll gelegentlich unsichtbar sein

  Alt 31. Jan 2014, 17:30
Die Gefahr besteht einfach darin, dass Du eine Bitmap selbst erzeugst und eine beschreibbare Property ohne Setter deklariert hast. Kleines Beispielprogramm:
Delphi-Quellcode:
type
  TTest1 = class
  private
    FBitmap: TBitmap;
  public
    constructor Create;
    destructor Destroy; override;
    (* ohne Setter *)
    property Bitmap: TBitmap read FBitmap write FBitmap;
  end;

  TTest2 = class
  private
    FBitmap: TBitmap;
    procedure SetBitmap(const Value: TBitmap);
  public
    constructor Create;
    destructor Destroy; override;
    (* mit Setter *)
    property Bitmap: TBitmap read FBitmap write SetBitmap;
  end;

{ TTest1 }

constructor TTest1.Create;
begin
  inherited;
  FBitmap := TBitmap.Create;
end;

destructor TTest1.Destroy;
begin
  FBitmap.Free;
  inherited;
end;

{ TTest2 }

constructor TTest2.Create;
begin
  inherited;
  FBitmap := TBitmap.Create;
end;

destructor TTest2.Destroy;
begin
  FBitmap.Free;
  inherited;
end;

procedure TTest2.SetBitmap(const Value: TBitmap);
begin
  (* Eigener Instanz Eigenschaften zuweisen *)
  FBitmap.Assign(Value);
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  Test: TTest1;
  Bitmap: TBitmap;
begin
  Bitmap := TBitmap.Create;
  try
    Test := TTest1.Create;
    try
      Test.Bitmap := Bitmap;
    finally
      Test.Free;
    end;
    Bitmap.Width := 100; //<- *Bumm*, wilder Zeiger und Speicherleck
  finally
    Bitmap.Free;
  end;
end;

procedure TForm1.Button2Click(Sender: TObject);
var
  Test: TTest2;
  Bitmap: TBitmap;
begin
  Bitmap := TBitmap.Create;
  try
    Test := TTest2.Create;
    try
      Test.Bitmap := Bitmap;
    finally
      Test.Free;
    end;
    Bitmap.Width := 100; //alles in Butter, da eigene Instanz
  finally
    Bitmap.Free;
  end;
end;
Detlef
"Ich habe Angst vor dem Tag, an dem die Technologie unsere menschlichen Interaktionen übertrumpft. Die Welt wird eine Generation von Idioten bekommen." (Albert Einstein)
Dieser Tag ist längst gekommen
  Mit Zitat antworten Zitat
Popov
(Gast)

n/a Beiträge
 
#4

AW: Bitmap soll gelegentlich unsichtbar sein

  Alt 1. Feb 2014, 10:56
Du hast ja Recht. Nur wie gesagt, dieses Problem war mir schon vorher bewusst, auch wenn mein letztes Beispiel ohne Setter und Getter war. Deshalb habe ich auch den Thread erstellt. Das tauschen einer Bitmap ist kein Problem, wie mein letztes Beispiel zeigt. Womit mein Problem eigentlich gelöst wäre. Aber entweder ich arbeite ohne Setter und Getter und riskiere das was du erwähnt hast, oder ich kopiere alles permanent mit Assign. Dann kostet das Zeit. Denn umsonst ist Assign nicht.
  Mit Zitat antworten Zitat
Benutzerbild von Sir Rufo
Sir Rufo

Registriert seit: 5. Jan 2005
Ort: Stadthagen
9.454 Beiträge
 
Delphi 10 Seattle Enterprise
 
#5

AW: Bitmap soll gelegentlich unsichtbar sein

  Alt 1. Feb 2014, 12:06
Ich weiß ja nicht ob das hier jetzt eine Posse wird ...

... mit dieser (schon mal von mir veröffentlichen Klasse)
Delphi-Quellcode:
unit DrawLayer;

interface

uses
  Windows,
  Graphics;

type
  TEnableBitmap = class( TBitmap )
  private
    FEnabled : Boolean;
  protected
    procedure Draw( ACanvas : TCanvas; const Rect : TRect ); override;
    procedure DrawTransparent( ACanvas : TCanvas; const Rect : TRect; Opacity : Byte ); override;
  public
    procedure AfterConstruction; override;
    property Enabled : Boolean read FEnabled write FEnabled;
  end;

  TDrawLayer = class
  private
    FBitmap : TBitmap;
    procedure SetBitmap( const Value : TBitmap );
    function GetBitmapEnabled : Boolean;
    procedure SetBitmapEnabled( const Value : Boolean );
  public
    procedure AfterConstruction; override;
    property Bitmap : TBitmap read FBitmap write SetBitmap;
    property BitmapEnabled : Boolean read GetBitmapEnabled write SetBitmapEnabled;
  end;

implementation

{ TEnableBitmap }

procedure TEnableBitmap.AfterConstruction;
begin
  inherited;
  FEnabled := True;
end;

procedure TEnableBitmap.Draw( ACanvas : TCanvas; const Rect : TRect );
begin
  if FEnabled then
    inherited;
end;

procedure TEnableBitmap.DrawTransparent( ACanvas : TCanvas; const Rect : TRect; Opacity : Byte );
begin
  if FEnabled then
    inherited;
end;

{ TDrawLayer }

procedure TDrawLayer.AfterConstruction;
begin
  inherited;
  FBitmap := TEnableBitmap.Create;
end;

function TDrawLayer.GetBitmapEnabled : Boolean;
begin
  Result := ( FBitmap as TEnableBitmap ).Enabled;
end;

procedure TDrawLayer.SetBitmap( const Value : TBitmap );
begin
  FBitmap.Assign( Value );
end;

procedure TDrawLayer.SetBitmapEnabled( const Value : Boolean );
begin
  ( FBitmap as TEnableBitmap ).Enabled := Value;
end;

end.
und der von dir angegebenen Testroutine
Delphi-Quellcode:
unit FormMain;

interface

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

type
  TMainForm = class( TForm )
    Panel1 : TPanel;
    Button1 : TButton;
    procedure Button1Click( Sender : TObject );
  end;

var
  MainForm : TMainForm;

implementation

{$R *.dfm}
{ TMainForm }

procedure TMainForm.Button1Click( Sender : TObject );
var
  Bmp : TBitmap;
begin
  with TDrawLayer.Create do
    try
      Bitmap.Canvas.Brush.Color := clRed;
      Bitmap.Width := 100;
      Bitmap.Height := 50;
      Self.Canvas.Draw( 0, 0, Bitmap );
      // Bis jetzt alles ok

      // Jetzt das Problem
      BitmapEnabled := False;
      // Man denkt sich nichts böses dabei, ist ja auch erlaubt
      Bmp := Bitmap;
      Bmp.Canvas.Ellipse( Bmp.Canvas.ClipRect );
      Self.Canvas.Draw( 100, 100, Bmp );

      // Nun stimmt nichts nicht überein. Wo ist die Ellipse?
      BitmapEnabled := True;
      Self.Canvas.Draw( 200, 200, Bitmap );
    finally
      Free
    end;
end;

end.
erhalte ich folgendes Ergebnis
dp_178696.PNG

Es macht genau das was du gefordert und beschrieben hast.

Warum du auf dem Assign rumreitest, kann ich nicht nachvollziehen. Wenn eine Eigenschaft mit Schreibzugriff eine Klasse ist, dann muss gewährleistet sein, dass dort kein Speicherleck auftritt.

Und es gilt auch die allgemeine Regel, wer die Instanz erzeugt ist auch für das Aufräumen zuständig. Andernfalls muss diese Aufgabe klar delegiert werden (z.B. Owner bei TComponent ).

Am einfachsten erreiche ich das durch das Kopieren der zugewiesenen Instanz (und TBitmap ist num mal auch ein TPersistent und bringt glücklicherweise ein funktionierendes Assign mit).

Und wie dir auffällt wird in deiner gesamten Testprozedur das Assign nicht einmal aufgerufen (weil ja direkt mit der Bitmap-instanz gearbeitet wird).
Also könnte die Eigenschaft Bitmap auch ReadOnly sein. Dann entfällt der Setter und damit das Assign (wenn es denn die/deine Augen stören sollte).

Bitte erläutere uns doch jetzt, was noch fehlt, denn dein Test wird zu 100% korrekt abgearbeitet.
Kaum macht man's richtig - schon funktioniert's
Zertifikat: Sir Rufo (Fingerprint: ‎ea 0a 4c 14 0d b6 3a a4 c1 c5 b9 dc 90 9d f0 e9 de 13 da 60)
  Mit Zitat antworten Zitat
Popov
(Gast)

n/a Beiträge
 
#6

AW: Bitmap soll gelegentlich unsichtbar sein

  Alt 2. Feb 2014, 16:55
Ich reite nicht auf Assign rum, auch habe ich nichts dagegen, nur gingen die Antworten von Anfang an in eine andere Richtung als die Frage ursprünglich gemeint war. Ich sehe den Fehler bei mir, ich denke ich habe die Frage missverständlich gestellt. Ich gehe jetzt aber auch nicht erneut drauf ein.

Bei dem Programm geht es um visuelle Darstellung von Informationen. Sowas gibt es schon, deshalb gibt es Erfahrungswerte. Hauptsächlich werden Polygone, Linien usw. gezeichnet, aber auch Bitmaps. Eigentlich sind die Bitmaps nur ein Extra, nicht das Eigentliche, aber falls sie eingefügt werden, wird es bei paar hundert Bitmaps eng und das Refresh kann dann Sekunden dauern. Somit ist alles was unnötig Zeit kostet nicht optimal, z. B. Assign.

Wenn ich also nun (im Fall der Fälle) mit paar hundert Bitmaps zu tun habe, dann stellt sich mir die Frage ob ich für jedes Refresh auch paar hundert Mal Bitmaps mit Assign hin und her kopieren möchte. Oder gibt es da eine bessere Möglichkeit?

Nun habe ich gerade 1 Million Assigns über eine 800*640 Pixel große Bitmap in einer Schleife ausgeführt. Entweder hat der Compiler erkannt, dass das Unsinn war und hat alles optimiert, oder Assign kostet kaum Zeit. Zumindest hat mein Test unter 100 Millisekunden gedauert. Erscheint mir wenig.

Vielleicht hatte ich einfach nur eine falsche Vorstellung von Assign und das Kopieren kostet wirklich kaum Zeit. In dem Fall ist es eine Option.

Was mein letztes Beispiel angeht, das sehe ich nicht als Fehler. Ich hab da bewusst auf Getter und Setter verzichtet, weil es in dem Beispiel nur um den Switch ging. Es war nur ein Test. Ein Getter und Setter war somit nicht nötig.
  Mit Zitat antworten Zitat
Antwort Antwort


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 05:10 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