Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Multimedia (https://www.delphipraxis.net/16-multimedia/)
-   -   Bitmap soll gelegentlich unsichtbar sein (https://www.delphipraxis.net/178696-bitmap-soll-gelegentlich-unsichtbar-sein.html)

Popov 21. Jan 2014 22:51

Bitmap soll gelegentlich unsichtbar sein
 
Ich hab eine Klasse die eine Bitmap Eigenschaft hat. Unter gewissen Bedingungen soll allerdings nichts ausgegeben werden. Sozusagen eine leere durchsichtige Bitmap. Auf der anderen Seite aber sollen die Eigenschaften bleiben, wie Breit, Höhe, Farbtiefe, usw. Und es muss ein TBitmap sein, also keine eigene abgeänderte Klasse. Es ist aber die Eigenschaft einer anderen Klasse. An der Stelle kann manipuliert werden.

Das hört sich nun leichter an als es dann tatsächlich ist. Vielleicht denke ich aber einfach auch nur zu kompliziert.

Da es eine Eigenschaft ist, kann man eigentlich einiges manipulieren. Zum Beispiel eine leere Ersatzbitmap mit kopierten Eigenschaften liefern, nur eben durchsichtig. Ausgabe falsche Bitmap, Eingabe in die richtige. 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.

Mit der Originalbitmap arbeiten, die vorher sichern und durchsichtig machen. Würde gehen, aber das abzufangen, ist ein gewisser Aufwand. Man müsste permanent zwischen Backup und Original hin und her kopieren.

Auch habe ich mit Canvas experimentiert, d. h. Bitmap bleibt, nur die Canvas wird geswitcht.

Das Beste ist bisher die zweite Idee, ist aber mit größeren Anpassungen an der Klasse verbunden.

Beim Blättern in der Hilfe habe ich dann Dormant entdeckt, ich verstehe es aber nicht so recht. Theoretisch genau was ich suche, zumindest nach dem Beispiel zu urteilen. Die Eigenschaften bleiben, nur wird nichts ausgegeben. Ändert man etwas, wird sie wieder sichtbar.

Wie gesagt, eigentlich was ich brauche, nur verstehe ich nicht was da im Hintergrund abgeht. Die OH habe ich zwar gelesen, sagt mir aber auch nicht viel.

Das wäre auch eine Möglichkeit, vorausgesetzt es macht tatsächlich was ich will.

Ober es gibt andere Ideen an die ich nicht gedacht habe.

sx2008 22. Jan 2014 00:39

AW: Bitmap soll gelegentlich unsichtbar sein
 
Du hast zwar viel über unsichtbare Bitmaps und Properties geschrieben aber kein Wort darüber verloren wozu das gut sein soll.
Und "Klasse" ist ebenfalls sehr abstrakt.
Willst du ein eigenes "Control" erstellen dann schreib' das auch so hin.
Es ist immer das gleiche Problem mit euch Programmierern:
Unpräzise Beschreibungen weil alle Details wegabstrahiert wurden bei gleichzeitig völlig verengtem Blick auf eine bestimmte Lösung.

Mach doch mal 2 Schritte zurück und fang mit der User Story an.

Popov 22. Jan 2014 01:39

AW: Bitmap soll gelegentlich unsichtbar sein
 
Weil eine andere Klasse auf diese Klasse mit der Bitmap zugreift. Ich hab zwei Möglichkeiten: ich setzte in der Klasse mit der Bitmap ein Boolean als Flag und die andere Klasse ignoriert bei False die Bitmap, was übrigens zurzeit wunderbar funktioniert, oder ich frage mich wieso eine andere Klasse einen Boolean erst auswerten muss, das ist doch OOP, warum liefert die Klasse mit der Bitmap im Falle von False nicht einfach eine leere Bitmap.

Es ist einfach nur eine Idee. Wozu steigt man auf einen Berg? Weil er da ist.

Volker Z. 22. Jan 2014 01:55

AW: Bitmap soll gelegentlich unsichtbar sein
 
Hallo,

ich habe jetzt die Fragestellung ein paar mal durchgelesen (werde aber nicht wirklich schlau daraus).

Du hast also eine Klasse, die Dir ein Bitmap kapselt und einen gewissen (irgendwie definierten) inneren Zustand hat.

Was hält Dich denn davon ab, in Abhängigkeit des "inneren Zustands Deiner Klasse", ein entsprechendes Bitmap im Getter auszuliefern - also nur dann eine Kopie des Original auszuliefern, wenn der Zustand erfüllt ist, ansonsten eine Kopie von irgendwas (leeres transparentes Bitmap o. ä.)?

Oder verstehe ich da was falsch?

Gruß

Popov 22. Jan 2014 02:39

AW: Bitmap soll gelegentlich unsichtbar sein
 
Zitat:

Zitat von Volker Z. (Beitrag 1244816)
werde aber nicht wirklich schlau daraus

Verstehe ich. Es ist eigentlich auch etwas ungewöhnlich eine leere Bitmap zu zeichnen.

Ich erkläre das mal vereinfacht - fast jede Komponente hat die Eigenschaft Visible. Ist sie True, wird sie angezeigt, ist sie False, nicht. Im Grunde will ich das auch für eine Bitmap.

Natürlich kann ich auch prüfen was unter Visible steht und die Bitmap ignorieren, muss dann aber eine Abfrage machen. Ich kann das aber auch der Bitmap überlassen. Ist sie False, soll sie nichts liefern, trotzdem aber ihre Eigenschaften behalten, wie Breite, Höhe, usw.

Wieso das mit der Kopie meiner Meinung nach nicht klappt, erkläre ich morgen.

sx2008 22. Jan 2014 04:20

AW: Bitmap soll gelegentlich unsichtbar sein
 
Zitat:

Zitat von Popov (Beitrag 1244817)
Ich erkläre das mal vereinfacht - fast jede Komponente hat die Eigenschaft Visible. Ist sie True, wird sie angezeigt, ist sie False, nicht. Im Grunde will ich das auch für eine Bitmap.

Du bist mächtig auf dem Holzweg und findest nicht mehr zurück.
Ein
Delphi-Quellcode:
TBitmap
ist eine Repräsentation von Bildpunkten im Speicher.
Zum Anzeigen wird entweder ein
Delphi-Quellcode:
TImage
oder eine
Delphi-Quellcode:
TPaintBox
benützt.
TImage und TPaintbox sind Controls (visuelle Steuerelemente).
Alles was kein Control ist hat prinzipiell keinen direkten Einfluss auf das was auf dem Bildschirm zu sehen ist.

Komm doch endlich mal auf den Punkt um was es geht.
Soll es ein Spiel werden mit mehreren Bitmaps die sich überlagern?
Benötigst du Sprites?

Popov 22. Jan 2014 07:52

AW: Bitmap soll gelegentlich unsichtbar sein
 
sx2008, bei allem Verständnis, was machst du da? Was stellst du für Fragen? Bist du gerade von einer Party zurück? Wo siehst du zwischen der ursprünglichen Frage und deiner letzten Feststellung einen Zusammenhang? Sorry, aber was für sinnfreien Rückfragen stellst du denn eigentlich? Wenn du den Sinn nicht verstehst, dann halt dich raus. Dass die Frage ungewöhnlich ist, ist mir selbst klar, aber wozu die Rückfragen? Wenn ich denn Sinn nicht verstehe was einer macht, dann beleidige ich ihn nicht zuerst in dem ich frage welchen Sinn seine Arbeit hat, sondern dann halte ich mich raus. Entschuldige, aber das verstehe ich wirklich nicht, bzw. mir fehlt da das Verständniss. Ich verstehe, dass meine Frage vielleicht sonderbar ist, aber was fällt dir ein mich zu hinterfragen, bzw. muss ich dich um Erlaubnis fragen muss ob und welche Funktionen ich in eine Klasse einbauen darf? Was hat dich das zu interessieren? Entweder du hast eine Antwort oder nicht.

Also, und nur weil mir das dann inzwischen doch aufträgt, weil ich mich nun anscheinend rechtfertigen muss, das Ganze ist eine popelige mehrschichtige Grafik, also eine Art Grafik mit Ebenen. Etwas was fast jedes Programm oberhalb von MS Paint.exe beherrscht, zeichnen auf verschiedenen Ebenen. Also eine Grafik bestehend aus verschiedenen Folien, also Folie1, Folie2, Folie3, usw. Zeichnet man etwas auf Folie2, hat das keine Auswirkung auf das was sich auf den anderen Folien befindet. Jedes CAD Programm kann das, Photoshop kann das, und Tausend andere Programme können das auch. Ebenen. Ist dir somit der Sinn der Klasse jetzt klarer? Darf ich das?

Und weil jede Ebene eine Bitmap zur Darstellung enthällt, und die Klasse aus mehreren Schichten besteht, ergibt das zum Schluss eine Gesamtgrafik. Und was schon seit Urzeit bei CAD und Photoshop möglich ist, das ist das abschalten von Ebenen. Das mache ich auch. Ich schalte einige Bitmaps gelegentlich ab.

Nur kann man das verschieden angehen: entweder ich prüfe einen Flag an der Bitmap (bzw. einer Klasse, denn jede Ebene ist eine Klasse die eine Bitmap enthält) ob sie sichtbar ist oder oder nicht - was ich bisher gemacht habe - oder, und das war ein neuer Ansatz, die Bitmap erkennt selbst, dass sie angeschaltet ist und liefert nichts.

Ist damit die Frage beantwortet oder brauche ich noch weitere Rechtfertigung für meine Klasse?

jaenicke 22. Jan 2014 08:15

AW: Bitmap soll gelegentlich unsichtbar sein
 
Ich würde eine Methode DrawLayer in der Ebenenklasse machen, die die Ebene zeichnet. Oder eben nicht. Die kann dann auch gleich die Transparenz berücksichtigen, sprich mit AlphaBlend zeichnen, usw.

Medium 22. Jan 2014 09:24

AW: Bitmap soll gelegentlich unsichtbar sein
 
Volker Z. hat imho schon die OOP-ige Lösung gegeben. Mal in Quasicode:
Delphi-Quellcode:
type
  TLayeredDingsbums = class
  private
    FEmptyBitmap: TBitmap;
    FLayers: TBitmapList;
    FLayerVisibility: TBooleanList;
  public
    function GetLayer(aLayerIndex: Integer): TBitmap;
  end;

implementation

function TLayeredDingsbums.GetLayer(aLayerIndex: Integer): TBitmap;
begin
  if FLayerVisibility[aLayerIndex] then
    result := FLayers[aLayerIndex]
  else
  begin
    if Assigned(FEmptyBitmap) then FreeAndNil(FEmptyBitmap);
    FEmptyBitmap := TBitmap.Create;
    FEmptyBitmap.Assign(FLayers[aLayerIndex]); // Um die Properties des Layers zu bekommen - billiger geht's natürlich mit einer eigenen Methode, die nur de gebrauchten übernimmt und nicht gleich alle Pixeldaten mit kopiert
    PaintTransparent(FEmptyBitmap);
    result := FEmptyBitmap;
  end;
end;
Ich habe das FEmptyBitmap als Feld der Klasse gewählt, damit nicht der Caller immer wieder Kopien freigeben muss, sondern die Bezitzerklasse konsistent sowohl ihre Layer als auch das gerade aktuelle "Leerbild" unter seiner Freigabegewalt hat. Man kann das sicherlich noch mit mehr "fancy" machen, aber das wäre mein Q&D Ansatz, der für den Caller völlig transparent (haha) ist.
Eine erste Besserung wäre z.B. dass man statt einer TBitmapList eine eigene kleine Klasse macht, die ein Bitmap und ein Bool enthält, und von dieser dann nur eine Liste zu verwalten braucht. (Das würde ich in der Realität glaube ich deutlich bevorzugen.)

Blup 22. Jan 2014 09:27

AW: Bitmap soll gelegentlich unsichtbar sein
 
Wenn Rückfragen kommen, die scheinbar nichts mit der eigenen Fragestellung zu tun haben, sollte man erst einmal überprüfen, ob das Thema wirklich verständlich genug dargestellt wurde. Ich bin aus der urspünglichen Fragestellung auch nicht schlau geworden.

Gewünscht wird scheinbar eine eigene Grafikklasse, die mehrere Layer unterstützt und für jeden Layer (neben der durch den Layer darzustellenden Grafik) weitere Eigenschaften speichert, die bei der Darstellung zu berücksichtigen sind. Diese Grundgerüst kann eventuell noch mit einer Ableitung von TImage und TPicture überbaut werden, die genau diese Grafikklasse published als Property bereitstellt und so die direkte Bearbeitung im Objektinspektor erlaubt.
Das Grundgerüst für die Grafikklasse könnte dann in etwa so ausschaun:
Delphi-Quellcode:
uses
  Graphics;

type
  TGraphicLayerList = class(TCollection)
  end;

  TLayerGraphic = class(TGraphic)
    constructor Create(AOwner: TComponent); override;
  private
    FLayer: TGraphicLayerList;
  protected
    procedure Draw(ACanvas: TCanvas; const Rect: TRect); override;
    {...zumindest alle abstrakten Methoden überschreiben...}
    procedure SetLayer(AValue: TGraphicLayerList);
  published
    property Layer: TGraphicLayerList read FLayer write SetLayer;
  end;

  TGraphicLayer = class(TCollectionItem)
    constructor Create(Collection: TCollection); override;
  private
    FRect: TRect;
    FVisible: Boolean;
    FPicture: TPicture;
    procedure SetRect(AValue: TRect);
    procedure SetVisible(AValue: Boolean);
    procedure SetPicture(AValue: TPicture);
  published
    property Rect: TRect read FRect write SetRect;
    property Visible: Boolean read FVisible write SetVisible;
    property Picture: TPicture read FPicture write SetPicture;
  end;

implementation

constructor TLayerGraphic.Create(AOwner: TComponent);
begin
  inherited;
  FLayer := TGraphicLayerList.Create(TGraphicLayer);
  {...}
end;

procedure TLayerGraphic.SetLayer(AValue: TGraphicLayerList);
begin
  FLayer.Assign(AValue);
end;

HHennig 22. Jan 2014 09:48

AW: Bitmap soll gelegentlich unsichtbar sein
 
Schau dir mal die GR32-Library an und im Besonderen TImage32 und ggf. dessen Nachfahren, dort gibt es Layering und es ist m. E. sehr gut gelöst.
Klar ist die ganze Library von Grund auf anders aufgebaut als TBitmap und Konsorten, aber vielleicht kannst du ja einige Denkanstöße entnehmen. In den mitgelieferten Examples gibt es auch ein Beispiel zu den Layern, ebenso ist das Prinzip in der CHM-DFatei ausführlich erläutert.
Ein wenig Spitzeln wie andere das machen ist ja erlaubt :wink:

Popov 22. Jan 2014 16:22

AW: Bitmap soll gelegentlich unsichtbar sein
 
Ok, vielleicht klingt mein erstes Post etwas verwirrend, vermutlich aber nur, weil ich mir einige Szenarien schon im Kopf durchgespielt habe und weiß, dass sie nicht funktionieren. Während es im ersten Moment für den Leser durchaus noch als machbar klingt. Natürlich stellt sich dann die Frage wo das Problem ist?

Ich hab gerade mein Gedankenspiel in Code umgesetzt um es zu prüfen. Hier das Problem mit einer leeren Ersatz-Bitmap.

Zuerst eine Beispielklasse:
Delphi-Quellcode:
type
  TKlasseB = class
  private
    FBitmap: TBitmap;
    FEmptyBitmap: TBitmap;
    FBitmapEnabled: Boolean;
  protected
    function GetBitmap: TBitmap;
  public
    constructor Create;
    destructor Destroy; override;
    property Bitmap: TBitmap read GetBitmap write FBitmap;
    property BitmapEnabled: Boolean read FBitmapEnabled write FBitmapEnabled;
  end;

constructor TKlasseB.Create;
begin
  FBitmap := TBitmap.Create;
  FBitmapEnabled := True;
  FEmptyBitmap := TBitmap.Create;
end;

destructor TKlasseB.Destroy;
begin
  FBitmap.Free;
  FEmptyBitmap.Free;
end;

function TKlasseB.GetBitmap: TBitmap;
begin
  if FBitmapEnabled then
    Result := FBitmap
  else
  begin
    Result := FEmptyBitmap;
    Result.Assign(FBitmap);
    Result.Canvas.Brush.Style := bsSolid;
    Result.Canvas.Brush.Color := Result.TransparentColor;
    Result.Transparent := True;
  end;
end;
Jetzt der Test
Delphi-Quellcode:
procedure TForm1.Button1Click(Sender: TObject);
var
  Bmp: TBitmap;
begin
  with TKlasseB.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;
Das Problem tritt nicht auf wenn man direkt mit der Bitmap der Klasse arbeitet. Vielleicht ist das Korinthenkacker, aber die Klasse ist in meinen Augen nicht wasserdicht. Man würde in dem Fall mit zwei verschiedenen Bitmaps arbeiten können.

Namenloser 22. Jan 2014 17:52

AW: Bitmap soll gelegentlich unsichtbar sein
 
Dann müsstest du dir eine eigene Klasse von TGraphic ableiten, die als Proxy für ein TBitmap dient.

jaenicke 23. Jan 2014 11:01

AW: Bitmap soll gelegentlich unsichtbar sein
 
Viel sinnvoller ist doch aber nur eine TBitmap zu nutzen pro Layer und den Layer selbst seinen Layer zeichnen zu lassen wie ich schon vorgeschlagen hatte. Dann ist das ganze sauber gekapselt, man kann die Layeroperationen auch gleich mit kapseln und das Problem mit mehreren Bitmaps gibt es auch nicht...

Popov 23. Jan 2014 14:33

AW: Bitmap soll gelegentlich unsichtbar sein
 
Du hast Recht, und im Grunde bin ich mit dem Punkt auch nicht glücklich. Nur ist für mich eine Klasse auch immer ein abgeschlossenes Gebilde, somit sollte eine zweite Klasse nicht etwas deuten was die erste versäumt hat.

Das Problem kommt davon, weil ich etwas, was im Grunde in eine Klasse gehört, aus Bequemlichkeit auf zwei Klassen verteilt habe. Und nun habe ich ein Kommunikationsproblem.

Ich denke ich lasse es so wie es bisher ist - in der einen Klasse ist ein Flag ohne weiter Eigenschaften. Die zweite Klasse richtet sich dann nach dem Flag ob sie den Layer beachten soll.

Das Ganze wird sonst zu fehleranfällig.

Sir Rufo 23. Jan 2014 15:04

AW: Bitmap soll gelegentlich unsichtbar sein
 
Versuch es mal hiermit.

Ich habe jetzt nur das Zeichnen verhindert, aber das könnte genauso gut auch umgeleitet werden auf ein leeres Bitmap mit der gleichen Größe ;)
Delphi-Quellcode:
  TLayerBitmap = class( TBitmap )
  private
    FCanDraw : Boolean;
  protected
    procedure Draw( ACanvas : TCanvas; const Rect : TRect ); override;
    procedure DrawTransparent(ACanvas: TCanvas; const Rect: TRect; Opacity: Byte); override;
  public
    property CanDraw : Boolean read FCanDraw write FCanDraw;
  end;

{ TLayerBitmap }

procedure TLayerBitmap.Draw( ACanvas : TCanvas; const Rect : TRect );
begin
  if not FCanDraw then
    Exit;
  inherited;
end;

procedure TLayerBitmap.DrawTransparent(ACanvas: TCanvas; const Rect: TRect; Opacity: Byte);
begin
  if not FCanDraw then
    Exit;
  inherited;
end;
Und das funktioniert deswegen, weil bei Delphi-Referenz durchsuchenTCanvas.Draw irgendwann einmal das hier aufgerufen wird
Delphi-Quellcode:
procedure TCanvas.Draw(X, Y: Integer; Graphic: TGraphic);
begin
  if (Graphic <> nil) and not Graphic.Empty then
  begin
    ...
    Graphic.Draw(Self, Rect(X, Y, X + Graphic.Width, Y + Graphic.Height));
    ...
  end;
end;
Und wenn man das sieht, dann weiß man auch, dass die Umleitung auf ein leeres Bitmap den gleichen Effekt hat, als wenn man das Zeichnen abbricht ;)

Darum sollte meine Bitmap-Ableitung genau das erfüllen, was dir da vorschwebt.

Popov 26. Jan 2014 12:06

AW: Bitmap soll gelegentlich unsichtbar sein
 
@SR

Der letzte Tipp ist für sich genommen ok, gute Idee, das Problem liegt aber im Detail. Vielleicht kann man das Problem lösen (bzw. vermutlich, denn im Grunde kann man alles lösen), aber die Bitmap muss eine TBitmap sein (also keine abgeleitete). Das liegt daran, dass andere Teile des Programms, bzw. andere Klassen eine TBitmap erwarten. Ich müßte also alles andere anpassen, und dafür ist das Programm inzwischen zu groß geworden.

Ich lasse vorerst die alte Lösung. Sie ist nicht schön, aber funktioniert.

Sir Rufo 26. Jan 2014 15:35

AW: Bitmap soll gelegentlich unsichtbar sein
 
Wieso, die Klasse erfüllt genau das, was du gefordert hast, auch in dem von dir beschriebenen Kontext
Delphi-Quellcode:
type
  TKlasseB = class
  private
    FBitmap: TLayerBitmap;
  protected
    function GetBitmap: TBitmap;
    procedure SetBitmap( const Value : TBitmap );
    function GetBitmapEnabled : Boolean;
    procedure SetBitmapEnabled( const Value : Boolean );
  public
    constructor Create;
    destructor Destroy; override;
    property Bitmap: TBitmap read GetBitmap write SetBitmap;
    property BitmapEnabled: Boolean read GetBitmapEnabled write SetBitmapEnabled;
  end;

constructor TKlasseB.Create;
begin
  inherited;
  FBitmap := TLayerBitmap.Create;
end;

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

function TKlasseB.GetBitmap: TBitmap;
begin
  Result := FBitmap;
end;

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

function TKlasseB.GetBitmapEnabled : Boolean;
begin
  Result := FBitmap.CanDraw;
end;

procedure TKlasseB.SetBitmapEnabled( const Value : Boolean );
begin
  FBitmap.CanDraw := Value;
end;

Popov 28. Jan 2014 22:28

AW: Bitmap soll gelegentlich unsichtbar sein
 
Jetzt nicht falsch verstehen, ich hab hier paar Ideen erfahren an die ich selbst nicht gedacht habe. Ich werde an dem Thema weiter arbeiten, aber aktuell drängt ein Termin und auch wenn auch die aktuelle Lösung mir persönlich nicht gefällt, sie funktioniert.

Ich weiß im Grunde auch nicht so richtig was ich wollte. Ich hab da das Beispiel unter Delphi-Referenz durchsuchenDormant gesehen und das brachte mich auf die Idee statt eine Bitmap nicht zu zeichnen, dafür keine Bitmap zu liefern.

Was ich nicht will ist Bitmaps hin und her kopieren. Das würde klappen, aber das wäre mit Kanonen auf Spatzen schießen. Irgendwie schwebte mir da ein leeres Nichts. Aber das mit Canvas ist schon eine gute Idee. Ich werde das mal testen. Vielleicht ist auch Dormant die Lösung, nur blicke ich nicht nicht 100% durch was im Hintergrund da passiert.

sx2008 29. Jan 2014 00:16

AW: Bitmap soll gelegentlich unsichtbar sein
 
Zitat:

Zitat von Popov (Beitrag 1245765)
Ich weiß im Grunde auch nicht so richtig was ich wollte.

Das hab ich schon gewußt als ich meinen ersten Betrag in diesem Thema geschrieben habe.
In meinem zweiten Betrag war ich auch nicht von einer Party zurück sondern nur genervt von deiner Art sämliche wichtige Informationen zurückzuhalten.
Wenn du einerseits nicht bereit bist eigene Ideen, die nicht funktionieren, zurückzustellen und andererseits nicht willens bist das ganze Problemumfeld zu beschreiben dann wirst du nie eine gute Lösung finden.

Popov 29. Jan 2014 01:12

AW: Bitmap soll gelegentlich unsichtbar sein
 
sx2008, du solltest den Satz nicht zu wörtlich nehmen. Natürlich wußte ich 100% was ich wollte, nur wenn man nicht weiß was technisch möglich ist, dann weiß man auch nicht wirklich was man - unter der Berücksichtigung des Möglichen - will.

Ich hab bereits im ersten Beitrag geschrieben "Dormant ... Theoretisch genau was ich suche". Einfach Beispiel angucken und schon hättest du erfahren was ich suche.

Da gibt es keine Informationen die ich versteckte. Es ist ein Programm mit dem man Objekte in einem Grafikfenster ablegen kann. Jedes Objekt kann mit einem Datensatz in einer einer oder mehreren Tabellen verknüpft werden. Womit die Datensätze visualisiert werden. Objekte können gruppiert werden, womit sie einer oder mehren Gruppen angehören. Womit man so ganz leicht auswerten kann welche Gruppen welche Datensätze enthalten. Man filtert die Ergebnisse somit nicht mit einem Filter, sondern durch Zuordnung von Gruppen. Womit wir bei Ebenen wären. Objekte können nach Bedeutung auf verschiedenen Ebenen abgelegt werden, womit sie zwar einer Gruppe angehören, aber man wiederum steuern kann ob sie bei der Auswertung beachtet werden...

Bist du jetzt schlauer?

Es ist einfach so (lassen wir die Informationen weg): da gibt es eine Bitmap, je nachdem ob sie dektiviert ist, soll sie gezeichnet oder nicht gezeichnet werden. Da gibt es zwei Möglichkeiten: der Teil des Programm, das die Bitmap zeichnet prüft nach ob er es zeichnen soll, oder, es prüft nichts, sondern zeichnet die Bitmap immer. In dem Fall brauche ich eine Zauberbitmap die im Fall, dass sie nicht gezeichnet werden soll, einfach nichts liefert. Wäre das Möglich, könnte man auf eine Prüfung verzichten.

Das war nur eine Idee, eine Bitmap die man abschalten kann.

Blup 29. Jan 2014 16:27

AW: Bitmap soll gelegentlich unsichtbar sein
 
Warum leitest du nicht einfach eine Klasse von TBitmap ab? Überall wo eine TBitamp erstellt werden soll, erstellst du statt dessen eine TZauberbitmap und fertig.
Delphi-Quellcode:
type
  TZauberbitmap = class(TBitmap)
    procedure Draw(ACanvas : TCanvas; const Rect : TRect); override;
  private
    FInvisible: Boolean;
  public
    property Invisible: Boolean read FInvisible write FInvisible;
  end;

procedure TZauberbitmap.Draw(ACanvas : TCanvas; const Rect : TRect);
begin
  if Invisible then
    Exit;

  inherited;
end;
Alternativ könntest du die Eigenschaft "Invisible" auch in der Ebenen-Klasse implementieren.
TZauberbitmap bekommt ein Property der Klasse Ebene (oder ein Interface) und kann darüber vor dem Zeichnen die Eigenschaft prüfen.
Es genügt dann die Eigenschaft bei der Ebene zu setzen und die Anzeige zu aktualisieren.

Ich gewinne den Eindruck das in deinem Projekt ein grundsätzliches Problem in der Trennung von Daten, Funktion und Oberfläche liegt.
Auch wenn sich einzelne Probleme umgehen lassen, wird das Ganze immer nur noch komplizierter.
Deine Versuche das nur an der Oberfläche zu lösen sind vermutlich langfristig zum scheitern verurteilt.

Sir Rufo 29. Jan 2014 16:58

AW: Bitmap soll gelegentlich unsichtbar sein
 
@Blup

Deine Lösung hatten wir schon in #18

Popov 29. Jan 2014 18:28

AW: Bitmap soll gelegentlich unsichtbar sein
 
Zitat:

Zitat von Blup (Beitrag 1245877)
Warum leitest du nicht einfach eine Klasse von TBitmap ab? Überall wo eine TBitamp erstellt werden soll, erstellst du statt dessen eine TZauberbitmap und fertig.

Jep, das ist eine Lösung, eine gute Lösung, auf die bin ich sogar selbst gekommen.

Das Problem: ich programmiere nicht das Programm nur Teile davon. Ich bekomme eine TBitmap und gebe eine TBitmap zurück. Wenn ich die Klasse ändern könnte, würde die Frage hier nicht stehen.

Was mir verschwebte war die Manipulation der TBitmap. Da das anscheinend nicht möglich ist, hat sich die Frage somit erledigt.

//EDIT:

Die Lösung #18 ist ok. So in der Art habe ich es auch schon versucht, es ist ja die einfachste Lösung. Die Möglichkeiten über Property habe ich. Der Grund wieso die Lösung noch in der Schwebe ist, ist das kopieren über Assign. Ich finde das übertrieben, will das aber nicht ganz ausschließen. Vielleicht liegt das daran, dass ich da eine gewisse Vorstellung habe. Wenn ich mich von der verabschiedet habe, werde ich evtl. offener sein.

Blup 30. Jan 2014 08:33

AW: Bitmap soll gelegentlich unsichtbar sein
 
Zitat:

Zitat von Popov (Beitrag 1245881)
Das Problem: ich programmiere nicht das Programm nur Teile davon. Ich bekomme eine TBitmap und gebe eine TBitmap zurück. Wenn ich die Klasse ändern könnte, würde die Frage hier nicht stehen.

Das schöne an der Vererbung ist, man kann eine TZauberbitmap auch als TBitmap zurückgeben.
Sie behält dabei ihr zauberhaftes Verhalten bei der Ausgabe unsichtbar oder sichtbar zu sein, ansonsten ist es eine ganz normale Bitmap.
Ist die Verknüfung mit der Ebene realisiert, kann die Ebene die Sichtbarkeit der Bitmaps in anderen Programmteilen fernsteuern, ohne das diese das besonders berücksichtigen müssten.
Ob das im konkreten Fall weiter hilft, kann ich natürlich nicht bewerten.

Ich seh grad irgendwie drehn wir uns im Kreis siehe #16, #17.
Warum bist du der Meinung deine Rückgabe darf nur eine TBitmap sein und keine abgeleitete Klasse?

Popov 31. Jan 2014 14:18

AW: Bitmap soll gelegentlich unsichtbar sein
 
Sorry für die späte Rückmeldung. Habe eigentlich schon kurz danach geantwortet, sogar einiges, aber anscheinend nicht abgeschickt.

Zum Thema: hier werden immer Tips gegeben, wofür ich dankbar bin, aber, vielleicht habe ich nicht viel drauf, aber einiges kann ich auch programmieren. Und eine Klasse in der ich die Bitmap abschalten kann, habe sogar ich drauf:
Delphi-Quellcode:
type
  TTestKlasse = class
  private
    FBitmap: TBitmap;
    FBackup: TBitmap;
    FVisible: Boolean;
  protected
    procedure SetVisible(AVisible: Boolean);
  public
    constructor Create;
    destructor Destroy; override;
    property Bitmap: TBitmap read FBitmap write FBitmap;
    property Visible: Boolean read FVisible write SetVisible;
  end;

constructor TTestKlasse.Create;
begin
  FBitmap := TBitmap.Create;
  FVisible := True;
  FBackup := nil;
end;

destructor TTestKlasse.Destroy;
begin
  FBitmap.Free;
  if FBackup <> nil then
    FBackup.Free;
end;

procedure TransparentBitmap(ABitmap: TBitmap);
var
  Brush: TBrush;
begin
  Brush := TBrush.Create;
  try
    Brush.Assign(ABitmap.Canvas.Brush);
    ABitmap.Canvas.Brush.Style := bsSolid;
    ABitmap.TransparentMode := tmFixed;
    ABitmap.Canvas.Brush.Color := ABitmap.TransparentColor;
    ABitmap.Transparent := True;
    ABitmap.Canvas.FillRect(ABitmap.Canvas.ClipRect);
    ABitmap.Canvas.Brush.Assign(Brush);
  finally
    Brush.Free;
  end;
end;

procedure TTestKlasse.SetVisible(AVisible: Boolean);
var
  Brush: TBrush;
begin
  if AVisible = FVisible then Exit;

  if AVisible then
  begin
    FBitmap.Assign(FBackup);
    FreeAndNil(FBackup);
  end
  else
  begin
    FBackup := TBitmap.Create;
    FBackup.Assign(FBitmap);
    TransparentBitmap(FBitmap);
  end;

  FVisible := AVisible;
end;

procedure TForm1.Button1Click(Sender: TObject);
const
  FilePath = 'C:\Programme\Gemeinsame Dateien\Borland Shared\Images\Splash\256Color\factory.bmp';
var
  Test: TTestKlasse;
begin
  Test := TTestKlasse.Create;
  try
    Test.Bitmap.LoadFromFile(FilePath);

    Test.Bitmap.Transparent := True;
    Canvas.Draw(0, Test.Bitmap.Height * 0, Test.Bitmap);

    Test.Visible := False;
    Canvas.Draw(0, Test.Bitmap.Height * 1, Test.Bitmap);

    Test.Visible := True;
    Canvas.Draw(0, Test.Bitmap.Height * 2, Test.Bitmap);
  finally
    Test.Free;
  end;
end;
Das Problem ist also nicht einen Schalter zu programmieren. Der Code oben funktioniert wunderbar, den habe ich als Übung bereits vor der Fragestellung geschrieben, nur er funktioniert nicht in allen Einzelheiten wie ich es mir vorgestellt habe. Was ich gesucht habe war mir eine evtl. unbekannte Eigenschaft von Bitmap. Ich kenne TBitmap zwar allgemein, aber nicht in Einzelheiten. Was ich bereits paar mal erwähnt habe ist Dormant. Wenn man sich das Beispiel anguckt, dann versteht man was mir eigentlich vorschwebte. Die Bitmap ist da, sie liefert aber nichts. Kaum aber schreibt jemand etwas rein, schon wird sie aktiviert, wird sichtbar und führt die Änderung durch.

Und das ist der Unterschied zum oberen Code. Wenn einer nicht vorher den Schalter wieder umstellt, zeichnet er ins leere. Zwar könnte man das abfangen und ein SetBitmap schreiben, aber der erste Zugriff würde immer ins Leere gehen. Es besteht also die Gefahr, dass in die falsche Bitmap geschrieben wird.

Kommen wir zu Vererbung. Entweder ich verstehe den Hinweis nicht oder man versteht nicht was mir vorschwebt. Allerdings ist die Diskussion inzwischen akademisch, da ich den Code bereits abgeliefert habe. Das bedeutet nicht, dass mich dass allgemein nicht interessiert. Trotzdem, wenn ich eine neue Klasse wollte, hätte ich sie programmiert. Aber wie ich bereits im Eingangspost gesagt habe, es soll TBitmap bleiben. Einigen wir uns vielleicht abschließend darauf, dass mir da etwas vorschwebte, mir allerdings der Wortschatz fehlt mein Problem zu beschreiben.

DeddyH 31. Jan 2014 14:26

AW: Bitmap soll gelegentlich unsichtbar sein
 
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.

Popov 31. Jan 2014 16:45

AW: Bitmap soll gelegentlich unsichtbar sein
 
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.

DeddyH 31. Jan 2014 17:30

AW: Bitmap soll gelegentlich unsichtbar sein
 
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;

Popov 1. Feb 2014 10:56

AW: Bitmap soll gelegentlich unsichtbar sein
 
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.

Sir Rufo 1. Feb 2014 12:06

AW: Bitmap soll gelegentlich unsichtbar sein
 
Liste der Anhänge anzeigen (Anzahl: 1)
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
Anhang 40647

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
Delphi-Quellcode:
TComponent
).

Am einfachsten erreiche ich das durch das Kopieren der zugewiesenen Instanz (und
Delphi-Quellcode:
TBitmap
ist num mal auch ein
Delphi-Quellcode:
TPersistent
und bringt glücklicherweise ein funktionierendes
Delphi-Quellcode:
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.

Popov 2. Feb 2014 16:55

AW: Bitmap soll gelegentlich unsichtbar sein
 
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.


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