![]() |
Schnell wiederholt in PaintBox zeichnen (Bitblt)
Hallo,
ich zeichne bei meinem ![]() Der Timer ist der aus MMSystems
Delphi-Quellcode:
Im Timer findet folgendes statt:
timer := timeSetEvent(25, 25, @UpdateFreq, 0, TIME_PERIODIC);
Delphi-Quellcode:
Jetzt passiert folgendes:
Spectrum:TBitmap;
BitBlt(MainForm.PaintBox1.Canvas.Handle, 0, 0, spectrum.width, Spectrum.height,spectrum.Canvas.Handle, 0, 0, SRCCOPY);
Allerdings habe ich durch zwischenzeitliches Speichern der Bitmap Spectrum erkannt, das diese durchgehend weitergezeichnet wird. Einzig das übertragen in die PaintBox scheint nicht zu funktionieren. Kann irgendjeman dieses Verhalten erklären und mir einen Tipp geben, wie ich das beheben kann? Vielen Dank! Viele Grüße, Benjamin |
Re: Schnell wiederholt in PaintBox zeichnen (Bitblt)
:gruebel:
Hm, schwer zu sagen das kann viele Ursachen haben. Wie zeichnest du auf das Bitmap und oder erstellst du irgend etwas was du nicht frei gibst ? PS.: Die Paintbox kann man auch weg lassen und direkt auhc den Canvas der Form zeichnen. |
Re: Schnell wiederholt in PaintBox zeichnen (Bitblt)
Zeichen ich direkt auf die Form passiert dasselbe.
Ich habe mit FastMM geprüft, ob ich irgendwas nicht freigebe. Offensichtlich nicht. Die einzigen Sachen die ich nutze sind FillRect und LineTo. |
Re: Schnell wiederholt in PaintBox zeichnen (Bitblt)
Kannst du die Zeichenrout. hier mal zeigen ?
|
Re: Schnell wiederholt in PaintBox zeichnen (Bitblt)
Wenn ich mich recht erinnere, muss das Zeichnen in die PaintBox im OnPaint-Event erfolgen, da die PaintBox keinen Speicher für den Zeicheninhalt bereitstellt.
In deinem Fall sollte im Timer-Ereignis lediglich PaintBox.Invalidate aufgerufen werden, während der BitBlt-Befehl im OnPaint der Paintbox stehen sollte. |
Re: Schnell wiederholt in PaintBox zeichnen (Bitblt)
Zitat:
Die Zeichenroutine sieht so aus:
Delphi-Quellcode:
procedure paintSpectrum;
var i: Integer; y: Integer; sc:INteger; //Skalierung; b0,b1:Integer; rect:TRect; avg:Single; begin //Fläche schwarz machen Rect.Left:=0; Rect.Top:=0; Rect.Right:=Spectrum.Width+1; Rect.Bottom:=Spectrum.Height+1; with Spectrum.Canvas do begin brush.Color:=clBlack; FillRect(Rect); end; //Jedes Band zeichnen b1:=1; for i := 0 to Bands - 1 do begin //Breite des Bandes b0:=b1-1; b1:=Trunc(Power(2, i * 10.0 / (BANDS - 1))); //Skalierungsfaktor sc:=10 + b1 - b0; //Wert des Bandes(skaliert) Y := Trunc((sqrt(MainForm.BandHistory[i,MainForm.Histposition-1] / log10(SC)) * 1.7 * Spectrum.Height) - 4); //Band zeichnen Rect.Left:=trunc(i*spectrum.width/bands); Rect.Top:=spectrum.Height-y; Rect.Right:=trunc((i+1)*spectrum.width/bands); Rect.Bottom:=spectrum.Height; with Spectrum.Canvas do begin //Ausgewähltes Band in Gelb, sonst grün if i=MainForm.SelectedBand then Brush.Color:=clYellow else Brush.Color:=clGreen; FillRect(Rect); end; //Durchschnitt des Bandes avg:=MainForm.AverageBandEnergy(MainForm.BandHistory[i]); //Durchschnittswert des Bandes einzeichnen Y := Trunc((sqrt(avg / log10(SC)) * 1.7 * Spectrum.Height) - 4); Spectrum.Canvas.Pen.Color:=clRed; Spectrum.Canvas.MoveTo(Rect.Left,Spectrum.Height-Y); Spectrum.Canvas.LineTo(Rect.Right,Spectrum.Height-Y); //Schwellwert einzeichnen Y :=Trunc((sqrt(avg*MainForm.DetectingFactor / log10(SC)) * 1.7 * Spectrum.Height) - 4); Spectrum.Canvas.Pen.Color:=clYellow; Spectrum.Canvas.MoveTo(Rect.Left,Spectrum.Height-Y); Spectrum.Canvas.LineTo(Rect.Right,Spectrum.Height-Y); end; //Auf Zeichenfläche übertragen BitBlt(MainForm.PaintBox1.Canvas.Handle, 0,0,spectrum.width,Spectrum.height,spectrum.Canvas.Handle, 0,0,SRCCOPY); end; |
Re: Schnell wiederholt in PaintBox zeichnen (Bitblt)
Ich kann mir vorstellen, dass der Timer sich hier quasi selbst überholt, die Zeichenroutine also ab und an noch zugange ist wenn schon der nächste Callback kommt. Das staut sich dann zusammen. Du könntest also einen Skip-Frame-Mechanismus einbauen: Kling moppig, wäre aber einfach nur das Abschalten der Reaktion auf den Timer wenn gerade gezeichnet wird.
Ein anderer Ansatz wäre es das zeichnen ähnlich wie in Spielen zu machen: Im Application.Idle Event. Um dabei nicht 100% CPU Last reinzubraten kann man mittels eines FPS Counters die FPS quasi künstlich drosseln. Timer sind zum Zeichnen immer so eine Sache, und selten eine gute ;) Edit: Ein dritter Weg wäre noch ein separater Zeichenthread der sich immer wieder mit Sleep(0) in der Dauerschleife "klein" hält. Auch hier wäre eine manuelle FPS-Begrenzung sinnvoll, und das letztliche Zeichnen auf den Zielcanvas sollte Synchronized gemacht werden. |
Re: Schnell wiederholt in PaintBox zeichnen (Bitblt)
Zitat:
Über die anderen Möglichkeiten muss ich mir mal Gedanken machen. Was ist denn groß der Unterschied zwischen dem Zeichnen im Timer und dem im OnIdle Event/eigenem Thread? In beiden Fällen wird doch regelmäßig gezeichnet, nur dass das beim Timer eben in festen Intervallen ist, oder? |
Re: Schnell wiederholt in PaintBox zeichnen (Bitblt)
Das mit dem Sich-Selbst-Überholen des Timers kannst du mit dem OnPaint-Ansatz ebenfalls lösen.
|
Re: Schnell wiederholt in PaintBox zeichnen (Bitblt)
Liste der Anhänge anzeigen (Anzahl: 1)
Auch hier wieder ein Offscreenbitmap basteln und in einem Timer etc. auf dieses Bitmap zeichnen lassen.
Das/die Bitmaps dann in der Paintbox zeichnen. Spectrum ist eine PaintBox ? Ich pers. verwende keine PaintBox, ist mir zu "dumm". ;) Beispiel:
Delphi-Quellcode:
Man kann sich das auch in eine Classe bauen bzw. formen.
implementation
{$R *.dfm} const VisXOffset = 50; VisYOffset = 40; procedure TForm1.FormCreate(Sender: TObject); begin bmp := TBitmap.Create; bmp.Width := 200; bmp.Height := 80; bmp.Canvas.Brush.Color := clBlack; RenderVisDone := True; end; procedure TForm1.Timer1Timer(Sender: TObject); begin if RenderVisDone and ASSIGNED(bmp) then begin RenderVis; bitblt(Canvas.Handle, VisXOffset, VisYOffset, bmp.Width, bmp.Height, bmp.Canvas.Handle, 0, 0, SRCCOPY); end; end; procedure TForm1.RenderVis; var i: integer; gt: Cardinal; begin RenderVisDone := False; bmp.Canvas.FillRect(bmp.Canvas.ClipRect); for i := 0 to bmp.Width div 4 - 1 do begin gt := GetTickCount; Windows.SetPixel(bmp.Canvas.Handle, i*4, round(bmp.Height div 2 + sin(gt/250+i)*15), RGB(255, 0, 0)); Windows.SetPixel(bmp.Canvas.Handle, i*4, round(bmp.Height div 2 + sin(gt/500-i)*20), RGB(128, 128, 255)); end; RenderVisDone := True; end; end. //Edit: Delphicodehighlightdingenbumensfehlfunktionskorrek tur .. |
Alle Zeitangaben in WEZ +1. Es ist jetzt 04:32 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