Autor Beitrag
Leto
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 98

XP
D7 Enterprise
BeitragVerfasst: Fr 22.10.04 11:44 
Auch ich hab mal wieder ein neues Poblem, für deren Lösung ich mich über Hilfe sehr freuen würde. Ich habe in meinem Programm eine Image auf der per mausklicks betsimmte Dinge geziechnet werden (in der Regel Bitmaps an die entsprechende Position). Das Image stellt auch eine kleine Animation dar, in der die Bilderchen hin un her zappeln. Um nach jeder Berechnugn neu zu zeichnen nehme ich das Hintergrundbild (eine Karte) und zeichne darauf alle Bilderchen mit ihren aktuellen Positionen. Anschliessend wird dieses Bild in das Image.Canvas reinkopiert (so iemlich alles über die BitBlt-Funktionen). Jetzt aber: Für manche Szernarien habe ich ein sehr sehr großes Bild (4 MB), welches ich als Hintergrundbild darstellen will. Ich lade es zu Beginn der Animation einmal in einem Bitmap. Doch jedes mal, wenn ich einen Animatiosnschritt mache und mit BitBlt das große Bild auf die Canvas reindonnere, duaert das fast eine Minute bis das Bild wirklich fertig drauf ist? Wie kann ich das beschleunigen (Flackern soll es natürlich nicht)? Kurz Was ist der schnellste Weg das große Bild auf die Canvas zu jagen? st es üblich nur den sichbaren Auschnitt des Bildes vielleicht rein zu kopieren und beim Scrollen diesen neu zu berechen?

_________________
Carpe Noctem
Andreas Pfau
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 997



BeitragVerfasst: Sa 23.10.04 21:58 
Hallo,

vermutlich ist dein TImage kleiner als dein Mega-Bitmap, oder? Du könntest ja dann deinen Backbuffer genausogroß machen wie das TImage. Wenn du jetzt deine Mini-Bilder in den Backbuffer kopierst wird immer nur der sichtbare Teil gezeichnet, der unsichtbare Teil verbrät dann nur ein paar Mikrosekunden. Drüfte mal zur Optimierung reichen, denke ich.

Ach ja, in TImage.Canvas zu zechen ist echt blöd, weil wenn das Form verdeckt wird und wieder sichtbar wird is alles futsch! nimm lieber ne TPaintBox und zeichne da bei PaintBox1.onPaint rein!

_________________
Life is a bad adventure, but the graphic is really good!
Leto Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 98

XP
D7 Enterprise
BeitragVerfasst: So 24.10.04 14:44 
Eine Antwort *freu*.

Allerdings habe ich die Ausführung nicht ganz erschlossen, was sicherlich an mir liegt. Also das TImage liegt in einer Scrollbox. Seine GRöße (des TImages) wird auf die Grösse des Hintergrundbildes gesetzt, damit der Benutzer alle Bereiche durch scrollen einsehen kann (dies ist im rahmen dieser Aufgabe unweigerliche Voraussetzung). ich zeichen alles erst in einem Bitmap-Objekt (sozusagen als Puffer) und erst wenn die BitBlt-Zeichenoperation abgeschlossen sind, wird der ganze Kram wieder über BitBilt auf die Canvas.Handle des Images übertragen. Das ist aber dennoch bei diesem sehr grossen Bild zu langsam. Von anderen Programmen wiess ich, dass dies auch scvhneller realisirbar ist. Dies muss ich irgendwie hinbekommen, denn das ist unzumutbar.

_________________
Carpe Noctem
Andreas Pfau
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 997



BeitragVerfasst: So 24.10.04 20:40 
Hallo,

also die Scrollbox-Lösung ist da mehr so die *faule Leute Lösung*. Warum? Nehmen mir mal an dein Bild wäre 1000x1000 Pixel groß, das macht bei 24bpp mal eben satte 2,9MB. Jetzt ist deine Scrollbox aber nur 300x300 Pixel größ, also nur 264kB.

Wenn du jetzt bei *jeder* Änderung immer den *gesamten* Backbuffer neu zeichnest hast du also über 2,8MB UMSONST gezeichnet, weil die nämlich nacher in der Scrollbox abgeschnitten werden!!!

Also, mach folgendes: Nimm statt der Scrollbox zwei Scrollbard, dessen Max-Wert du dynamisch anpassen musst (ich glaube mit ein paar Modifikationen der Scrollbox gehts auch damit). Auf jeden Fall darf dein Zielbitmap NUR so groß sein wie der tatsächlich angepasste Bereich!

Dann gehts ganz einfach, wenn du z.B. zum Punkt 300x200 gescrollt hast verschiebst du alle Zeichenoperationen im Frontbuffer um 300 Pixel nach links (aus dem sichtbaren Breich raus!) und eben 200 Pixel nach oben.

So, jetzt erkennt Windows (wer sonst rendert wohl für dich?) dass da seeeeeeeeeehr viel unsichtbar ist und lässt das Zeichen mal schön bleiben. Es werden nur die 264kB, die sichtbar sind, gezeichnet.

Also, folgendes Ändern, mal zusammengefasst:
- Dein Image (die Paintbox bitte!) nur so groß wie der angezeigte Bereich
- Scrollbars manuell parametrieren (Scrollweite = Gesamtbreite - Sichtbare Breite, entsprechendes für Höhe)
- Beim Scrollen die Scrollposition von der Zeichenposition abziehen

Ich hoffe ich habe das mal mehr oder weniger anschaulich rüberbringen können :wink:

_________________
Life is a bad adventure, but the graphic is really good!
Leto Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 98

XP
D7 Enterprise
BeitragVerfasst: So 24.10.04 21:30 
Klintg schon mal alles sehr gut. Ich werde morgen soafort daran gehen und es probieren. Die Ausführung erscheint mir logisch. Ich halte hier auf dem laufenden, wie es ausgeht.

Ich weiss blos noch nicht ganz, warum immer zur TPaintBox anstelle zum TImage geraten wird. Ist das nicht egal, ob ich nun eine Zeichen-Methode für TImage habe oder alles im onPaint der PaintBox erledige?

Ich darf annehmen der Backbuffer ist die TBitmap-Instanz in der ich erstmal reinzeichne und diese dann anschliessend dem Image überbrate?

_________________
Carpe Noctem
zorxx
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 21

Win XP, GNU/ Linux
D7 Ent
BeitragVerfasst: Mo 25.10.04 00:54 
Die TPaintBox hat den Vorteil schneller zu sein als TImage.
Nachteil ist aber das TPainBox sich nicht automatisch refresht, welches TImage macht.
Aber dafür gibts ja das OnPaint ;)

Noch nen Tipp für dich,

www.derentwickler.de...k_t4164e9beb2360.zip

dort ist ein schmuckes Beipiel zu dem was der Andreas beschrieben hat.

Gruss

zorxx

_________________
Keine Panik!
Andreas Pfau
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 997



BeitragVerfasst: Mo 25.10.04 20:50 
Hallo,

@zorxx, es liegt net in meiner Natur besserwisserisch zu sein (OK, ich gebs ja zu, ich bins :wink: ) aber warum ich zur TPaintBox riet hat 2 Vorteile:
1) Es wird ja eh ein Backbuffer verwendet, ein TImage wäre reine Ressourcenverschwendung
2) Es ist *gefährlich* in Timage.Canvas zu zeichnen, denn wenn das Form mal kurz verdeckt wird, ist der Bildbereich futsch. Also wenn schon TImage, dann bitte so:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
Image1.Bitmap.Assign(BackBuffer); // Parameter wie Höhe, Breite, Pixelformat übernehmen

{ ... }

Image1.Pixture.Bitmap.Canvas.Draw(X, Y, BackBuffer); // In das BITMAP-Canvas zeichnen!!!

Ich mach das auch manchmal so, aber nur zum was probieren, wenn es dann zur "richtigen" Anwendung geht bitte inne Paintbox.

Ach ja, @zorxx, TPaintBox ist natürlich auch SCHNELLER (eben wegen dieser unnötigen Operationen). Nicht dass jemand behauptet isch würde dich totschweigen 8)

_________________
Life is a bad adventure, but the graphic is really good!
zorxx
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 21

Win XP, GNU/ Linux
D7 Ent
BeitragVerfasst: Di 26.10.04 01:24 
*fg*

@Andreas, kann es sein das du bei Vorteil 2 etwas verwechselt hast. Wenn ich in ein TImage was rein male und das Fenster überblende ist es immer noch da.

Gruss

zorxx

PS: Bin auch nicht besserwisserlich :)
(Glaube das ganze wird jetzt aber OT)

_________________
Keine Panik!
Andreas Pfau
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 997



BeitragVerfasst: Di 26.10.04 13:25 
Hallo,

ich versteh net ganz - hab mir mal folgenden code zusammnengeschustert:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
  with image1.canvas do
  begin
    brush.color:=clred;
    rectangle(10,20,130,140);
    brush.color:=clblue;
    rectangle(20,10,140,130);
  end;

Wenn ich das fenster unter die taskleiste schiebe und danach wieder hochhole ist der inhalt futsch. welche delphi-verison hast du? hast du irgendwas and en propertys genändert?

(delphi7prof)

_________________
Life is a bad adventure, but the graphic is really good!
zorxx
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 21

Win XP, GNU/ Linux
D7 Ent
BeitragVerfasst: Di 26.10.04 14:33 
Hallo,

also ich benutzte Delphi7 Ent, kann aber auch sagen, dass es sich bei Delphi4 Pro und Delphi8 Arch (VCL.NET) genauso verhält. An den Eigenschaften habe ich nichts geändert.

Aber ich dachte immer das wäre ein Hauptfeature von der TImage Komponente. Wenn man ein Bild darstellt, will man ja auch nicht bei jedem WM_PAINT das Bild neu einladen.

Aus der Implementierung geht hervor, dass TImage eine Klassenvariable FPicture: TPicture; besitzt. Wenn ich das jetzt richtig verstanden habe (Code nur überflogen) wird sogar auf dieser Canvas gezeichnet. Das wäre dann ja der Backbuffer für die Grafik.

Gruss

zorxx

_________________
Keine Panik!
Andreas Pfau
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 997



BeitragVerfasst: Di 26.10.04 16:06 
Hallo,

Auszug aus der Unit "ExtCtrls":
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
procedure TImage.Paint;
var
  Save: Boolean;
begin
  if csDesigning in ComponentState then
  with inherited Canvas do
  begin
    Pen.Style := psDash;
    Brush.Style := bsClear;
    Rectangle(00, Width, Height);
  end;
  Save := FDrawing;
  FDrawing := True;
  try
  with inherited Canvas do
    StretchDraw(DestRect, Picture.Graphic);
  finally
  FDrawing := Save;
  end;
end;

Wie man erkennen kann wird der Image.Picture.Graphic drübergezichnet. Fazit: zeichnet man auf TImage.Canvas ist der Inhalt beim nächsten Neuzeichnen nicht mehr vorhanden und kann nicht aktualisiert werden.

Dein Backbuffer ist schon OK, aber das heißt noch lange nicht dass du auf das Canvas des TImage zeichnen darfst - wenn schon dann in den Backbuffer selbst.

Aber insofern hast du schon Recht. Man kann...
- einen eigenen Backbufer (also ein TBitmap) anlegen und diesen onPaint in eine TPaintBox kopieren
- oder das Picture.Bitmap eines TImage als Backbuffer verwenden

Bringt organisatorische Vorteile mit sich in das Bitmap des Images zu zeichnen, muss ich zugeben... :idea:

_________________
Life is a bad adventure, but the graphic is really good!