![]() |
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. |
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 ![]() |
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. |
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ß |
AW: Bitmap soll gelegentlich unsichtbar sein
Zitat:
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. |
AW: Bitmap soll gelegentlich unsichtbar sein
Zitat:
Ein
Delphi-Quellcode:
ist eine Repräsentation von Bildpunkten im Speicher.
TBitmap
Zum Anzeigen wird entweder ein
Delphi-Quellcode:
oder eine
TImage
Delphi-Quellcode:
benützt.
TPaintBox
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 ![]() |
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? |
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.
|
AW: Bitmap soll gelegentlich unsichtbar sein
Volker Z. hat imho schon die OOP-ige Lösung gegeben. Mal in Quasicode:
Delphi-Quellcode:
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.
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; 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.) |
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; |
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: |
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:
Jetzt der Test
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;
Delphi-Quellcode:
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.
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; |
AW: Bitmap soll gelegentlich unsichtbar sein
Dann müsstest du dir eine eigene Klasse von TGraphic ableiten, die als
![]() |
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...
|
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. |
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:
Und das funktioniert deswegen, weil bei
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; ![]()
Delphi-Quellcode:
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 ;)
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; Darum sollte meine Bitmap-Ableitung genau das erfüllen, was dir da vorschwebt. |
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. |
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; |
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 ![]() 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. |
AW: Bitmap soll gelegentlich unsichtbar sein
Zitat:
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. |
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. |
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:
Alternativ könntest du die Eigenschaft "Invisible" auch in der Ebenen-Klasse implementieren.
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; 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. |
AW: Bitmap soll gelegentlich unsichtbar sein
|
AW: Bitmap soll gelegentlich unsichtbar sein
Zitat:
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. |
AW: Bitmap soll gelegentlich unsichtbar sein
Zitat:
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? |
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:
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.
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; 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. |
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.
|
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. |
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; |
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.
|
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:
und der von dir angegebenen Testroutine
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.
Delphi-Quellcode:
erhalte ich folgendes Ergebnis
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. 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:
ist num mal auch ein
TBitmap
Delphi-Quellcode:
und bringt glücklicherweise ein funktionierendes
TPersistent
Delphi-Quellcode:
mit).
Assign
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. |
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