Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Multimedia (https://www.delphipraxis.net/16-multimedia/)
-   -   Delphi Canvas flackern bei VCL Styles (https://www.delphipraxis.net/176705-canvas-flackern-bei-vcl-styles.html)

TTF 21. Sep 2013 15:52

Canvas flackern bei VCL Styles
 
Hallo,
Mein Problem ist Folgendes:
Ich zeichne per Canvas auf eine PaintBox, wenn ich aber einen anderen VCL-Style als den Windows Standard Style verwende werde ich trotz der eingeschalteten Property DoubleBuffered mit einem hässlichen Flackern konfrontiert. Im Windows Style läuft aber alles flüssig.
Weiss jemand woran das liegen könnte beziehungsweise, wie man das beheben könnte? Oder ist das ein Bug der IDE?
Bin für jede Antwort dankbar
Liebe Grüsse
TTF

Volker Z. 21. Sep 2013 23:17

AW: Canvas flackern bei VCL Styles
 
Hallo,

Zitat:

Ich zeichne per Canvas auf eine PaintBox, [...]
Was zeichnest Du?
Zitat:

Bin für jede Antwort dankbar
Wir wären für jeden weiteren Input dankbar.

Ich lege mir eine Paintbox und ImageList (14 Bitmaps 256x256 Pixel) auf ein Formular und lass mir mal was in der Paintbox zeichnen
Delphi-Quellcode:
procedure TForm1.PaintBox1Paint(Sender: TObject);
var
  i, j : Integer;
begin
  for i := 0 to 10 do
    for j := 0 to ImageList1.Count - 1 do
      ImageList1.Draw (PaintBox1.Canvas, Random (Width), Random (Height), j, True)
end;
egal welchen Style ich verwende, da flackert nix, da ruckelt nix.

Zurück zur Frage: Was zeichnest Du?

Code wäre da sicherlich recht hilfreich.

Gruß

TTF 22. Sep 2013 00:44

AW: Canvas flackern bei VCL Styles
 
Danke für die Antwort. Ich zeichne eine Waveform mithilfe der Bass.dll. Ganz ähnlich wie im custloop Sample.
Vielleicht liegt es daran, dass ich das ganze mit einem Timer recht häufig update. Ich wüsste jedoch nicht, warum es dann nur bei Windows style funktionieren sollte.
Der Vorgang dabei ist folgender:
Ich scanne die Peaks von der Audiodatei und übertrage dann Linie für Linie die Waveform auf ein TBitmap, das ich dann in die PaintBox malen lasse.
Ist daran etwas falsch oder so?
Code kann ich Grade leider nicht geben, da ich nicht am Computer bin. Ich glaube ohnehin nicht, dass es auf ein Detail im Code ankommt, sondern auf das Prinzip. Falls es aber nötig ist, editiere ich gerne noch etwas rein.
Liebe Grüsse
TTF

Medium 22. Sep 2013 01:48

AW: Canvas flackern bei VCL Styles
 
Flackern + TPaintbox = Es wird sehr wahrscheinlich nicht im OnPaint der Paintbox gezeichnet. Richtig wäre es daher im Timer (der kann praktisch nicht zu schnell sein) nur das das Bitmap neu zu zeichnen, und dann TPaintbox.Invalidate aufzurufen. Im TPaintbox.OnPaint Ereignis sollte dann das Bitmap auf den Paintbox-Canvas geblittet werden. Das wäre auch unabhängig von Styles der saubere Weg.

cltom 22. Sep 2013 07:09

AW: Canvas flackern bei VCL Styles
 
Zitat:

Zitat von Medium (Beitrag 1229417)
Flackern + TPaintbox = Es wird sehr wahrscheinlich nicht im OnPaint der Paintbox gezeichnet. Richtig wäre es daher im Timer (der kann praktisch nicht zu schnell sein) nur das das Bitmap neu zu zeichnen, und dann TPaintbox.Invalidate aufzurufen. Im TPaintbox.OnPaint Ereignis sollte dann das Bitmap auf den Paintbox-Canvas geblittet werden. Das wäre auch unabhängig von Styles der saubere Weg.

Auch wenn das schon im Großen und Ganzen gut beschrieben ist, ein Codebeispiel wäre super dazu. So ganz nachvollziehen kann ich es noch nicht. Du erzeugtst eine zweite Bitmap, auf die zeichnet man im Timer-Event? Und die kopiert man im OnPaint der Paintbox?

TTF 22. Sep 2013 08:16

AW: Canvas flackern bei VCL Styles
 
Also das Codeschnipsel:):

Delphi-Quellcode:
procedure TForm1.Timer1Timer(Sender: TObject);
begin
  if Buffer.Width <> PaintBox1.Width then
  begin
    Buffer.Width := PaintBox1.Width;
    StartPeakScan;
  end
  else
  begin
    Buffer.Width := PaintBox1.Width;
    Buffer.Height := PaintBox1.Height;
    DrawSpectrum;
  end;

  PaintBox1.Refresh;
end;

//und dann Painten

procedure TForm1.PaintBox1Paint(Sender: TObject);
begin
  PaintBox1.Canvas.Draw(0, 0, Buffer);
end;
Weiss jemand woran es liegen könnte?

Der schöne Günther 22. Sep 2013 13:27

AW: Canvas flackern bei VCL Styles
 
Delphi-Quellcode:
If Buffer.Width = PaintBox1.Width then Buffer.Width := Paintbox1.Width
Warum?

Auch: Vielleicht habe ich es nicht ganz verstanden. Aber XE4. Warum nicht mit TChart?

Hast du mal die Zeit gemessen, wie lange ein Timerdurchlauf benötigt? Und: Hast du mal versucht, zur Laufzeit den VCL-Stil zu wechseln? Wie verhält es sich dann?

TTF 22. Sep 2013 14:00

AW: Canvas flackern bei VCL Styles
 
Zitat:

Zitat von Der schöne Günther (Beitrag 1229475)
Delphi-Quellcode:
If Buffer.Width = PaintBox1.Width then Buffer.Width := Paintbox1.Width
Warum?

Das habe ich nirgends geschrieben. Ich habe geschrieben:
Delphi-Quellcode:
if Buffer.Width <> PaintBox1.Width then Buffer.Width := Paintbox1.Width
, um beim Resizing die Grösse des Bildes der PaintBox anzupassen.

Zitat:

Zitat von Der schöne Günther (Beitrag 1229475)
Auch: Vielleicht habe ich es nicht ganz verstanden. Aber XE4. Warum nicht mit TChart?

Wenn das einfacher geht, dann sehr gerne. Ich habe nur leider noch nie mit TChart gearbeitet, daher bräuchte ich hier auch wieder eine Erklärung.

Zitat:

Zitat von Der schöne Günther (Beitrag 1229475)
Und: Hast du mal versucht, zur Laufzeit den VCL-Stil zu wechseln? Wie verhält es sich dann?

Leidere genau gleich. Ich nehme an, es liegt nicht am Code. Ich habe den Style hiermit geändert:
Delphi-Quellcode:
procedure TForm1.Button4Click(Sender: TObject);
begin
   if Assigned(TStyleManager.ActiveStyle) and (TStyleManager.ActiveStyle.Name<>'Windows') then begin
   TStyleManager.TrySetStyle('Windows');
 end else begin
   TStyleManager.TrySetStyle('Amakrits');
 end;
end;
ICh weiss wirklich nicht mehr weiter.

Der schöne Günther 22. Sep 2013 14:20

AW: Canvas flackern bei VCL Styles
 
Zitat:

Zitat von TTF (Beitrag 1229486)
Das habe ich nirgends geschrieben. Ich habe geschrieben:
Delphi-Quellcode:
if Buffer.Width <> PaintBox1.Width then Buffer.Width := Paintbox1.Width
[...]

Ja, und im Else-Zweig schreibst du es nochmal.

Delphi-Quellcode:
if Buffer.Width <> PaintBox1.Width then
   begin
     Buffer.Width := PaintBox1.Width; <-- Wenn ungleich, ...
     StartPeakScan;
   end
   else
   begin
     Buffer.Width := PaintBox1.Width; <-- Wenn gleich, dann auch
     Buffer.Height := PaintBox1.Height;
     DrawSpectrum;
   end;

Zitat:

Zitat von TTF (Beitrag 1229486)
Ich habe nur leider noch nie mit TChart gearbeitet, daher bräuchte ich hier auch wieder eine Erklärung

Ich weiß nicht, wieviel du mit grafischen Anzeigen und Diagrammen machst, aber ich denke auf jeden Fall, das sich das lohnt. Es ist eine tolle Komponente die sich um das Zeichnen an sich vollständig kümmert. (Automatische oder manuelle) Achsenskalierung, Linien, Punkte, Balken, was auch immer. Eigentlich ist schon in der normalen Variante alles drin. Ich weiß nicht ob bei den Delphi-Beispielen etwas dabei ist, aber ich hatte mit TChart auch erst Null Erfahrung aber nach keinen 10 Minuten weiß man, wie es geht.
Ich schwafele nur und kann kein konkretes Tutorial geben, würde aber trotzdem mit Nachdruck empfehlen, da bei naher Gelegenheit unbedingt reinzuschauen. Ich finde, man kann damit wirklich eine große Menge Zeit sparen!


Blöd mit der Paintbox. Meine einzige Erklärung wäre gewesen, dass das Zeichnen des Formulars wegen den Stilen entsprechend länger dauert und dein Timer zu oft feuert. Kannst du den vlt. etwas herunterdrehen? Vielleicht könntest du die Paintbox manuell einfrieren? Wenn ich es richtig in Erinnerung habe, könntest du, an der VCL vorbei, mittels
Delphi-Quellcode:
SendMessage
nach (oder vor?) der Neuberechnung ein
Delphi-Quellcode:
WM_SETREDRAW
mit
Delphi-Quellcode:
LParam = 0
zum Einfrieren und im onPaint wieder mit 1 zum Aufwachen schicken.

Ich sehe nur, dass ich in meiner Anwendung bestimmt bald ein Dutzend TCharts habe und die funktionieren auch beim Live-Wechsel des VCL-Stils weiterhin und flackern nicht.

Vielleicht kannst du mit dem Debugger durchwandern und finden, wo bzw. wann es flackert? Wie hängt die Timer-Geschwindigkeit damit zusammen? Statt Paintbox.Refresh mal PaintBox.Invalidate probiert?

TTF 22. Sep 2013 21:23

AW: Canvas flackern bei VCL Styles
 
Liste der Anhänge anzeigen (Anzahl: 1)
Danke erstmal für die Hilfe. Ich habe den Timer nun auf 200ms zurückgesetzt. Nun sind nur noch vereinzelt Flackern(aber trotzdem zuviel) zu sehen. Es scheint wirklich mit dem Timer zusammenzuhängen, aber nicht mal darauf kann man gehen. Das Ding flackert oder nicht, wie die GPU gerade lustig ist. Bei 400ms ist das Ergebnis schon fast anschaubar, aber natürlich dauert das Zeichnen beim Laden oder resizen. Es flackert 'nur' noch alle 4-5 sekunden. Und so geht das weiter (600ms => 6-7sec). Aber das kann es kann ja irgendwie nicht sein:x. Ich gebe ja zu, ich habe einen Laptop und vielleicht nicht die Beste Grafikkarte, aber so ein Bisschen Wellenlinien könnte man doch schon aushalten:|, zumal man als liebe liebe GPU bei transparenten Fenstern(Windows aero) imho sich sogar noch ein bisschen mehr anstrengen muss, als bei den nicht transparenten.
Hat jemand ein gutes Tutorial für TChart, weil das ja sein soll?
Ich hänge mal das ganze Projekt an(ist eig nur ein Testprojekt) an:
Wegen dem doppelten Buffer.width. ja, was soll man sagen :stupid:.
Falls jemand Zeit hat sich das anzuschauen, bin ich dankbar.

jfheins 22. Sep 2013 21:40

AW: Canvas flackern bei VCL Styles
 
Hast du mal probiert statt
Delphi-Quellcode:
PaintBox1.Refresh;
wirklich
Delphi-Quellcode:
PaintBox1.Invalidate;
zu benutzen?

Und eventuell könnte man noch versuchen, direkt BitBlt oder StretchBlt aufzurufen, statt Canvas.Draw. (Aber erst danach)

TTF 23. Sep 2013 16:02

AW: Canvas flackern bei VCL Styles
 
PaintBox1.Invalidate habe ich auch schon versucht.
Von BitBlt und StretchBlt habe ich ehrlich gesgt noch nie was gehört:oops::lol:

cltom 23. Sep 2013 16:16

AW: Canvas flackern bei VCL Styles
 
Das wär echt Weltklasse, wenn einer so ein Beispiel-Projekt machen könnte, das die Benutzung der zweiten Bitmap, das blitten und wie man das mit dem Timer steuert, veranschaulicht. Ich hab's leider auch noch nicht ganz kapiert. Wo wird invalidate aufgerufen, was wird im Timer gemacht, was im OnPaint der PaintBox, wo wird geblittet, wie?

Vielleicht hat einer ein Erbarmen, das wär spitze, danke im Voraus!

EWeiss 23. Sep 2013 18:36

AW: Canvas flackern bei VCL Styles
 
Zitat:

Zitat von cltom (Beitrag 1229643)
Das wär echt Weltklasse, wenn einer so ein Beispiel-Projekt machen könnte, das die Benutzung der zweiten Bitmap, das blitten und wie man das mit dem Timer steuert, veranschaulicht. Ich hab's leider auch noch nicht ganz kapiert. Wo wird invalidate aufgerufen, was wird im Timer gemacht, was im OnPaint der PaintBox, wo wird geblittet, wie?

Vielleicht hat einer ein Erbarmen, das wär spitze, danke im Voraus!

Ist ja kein problem.
Nur ich habe kein XE.. sorry ;)

Vielleicht bringt es was wenn du deinen eigenen DoubleBuffer erstellst?
Ka. Ob der in den Styles fehlerhaft ist.

gruss

Volker Z. 24. Sep 2013 00:15

AW: Canvas flackern bei VCL Styles
 
Hallo,

hast Du schon mal folgendes versucht (ich beschränke mich auf das Wesentliche, ansonsten Dein Code wie gehabt)
Delphi-Quellcode:
procedure TForm1.DrawSpectrum;
begin
  // clear background
  Buffer.Canvas.Brush.Color := TStyleManager.ActiveStyle.GetStyleColor (scWindow);
  Buffer.Canvas.FillRect(Rect(0, 0, Buffer.Width, Buffer.Height));

  // Rest wie gehabt
end;
Gruß

TTF 24. Sep 2013 20:26

AW: Canvas flackern bei VCL Styles
 
Habe ich getestet mit dem selben Ergebnis.:|

EWeiss 25. Sep 2013 15:52

AW: Canvas flackern bei VCL Styles
 
Zitat:

Zitat von TTF (Beitrag 1229804)
Habe ich getestet mit dem selben Ergebnis.:|

Check das!
Mein Kumpel war so freundlich mich an sein XE4 zu lassen
Als Hobby Schreiber ist mir das einfach zu teuer.

gruss

TTF 25. Sep 2013 20:19

AW: Canvas flackern bei VCL Styles
 
Hallo EWeiss
Herzlichsten Dank, dass du dir exra die Mühe gemacht hast. Es funktioniert top:thumb:.
Könntest du mir bitte noch sagen, wo meine Fehler lagen?
Danke und liebe Grüsse
TTF

EWeiss 25. Sep 2013 20:24

AW: Canvas flackern bei VCL Styles
 
Zitat:

Zitat von TTF (Beitrag 1229928)
Könntest du mir bitte noch sagen, wo meine Fehler lagen?

Es liegen mehrere probleme vor warum dein Quelltext auf der Basis nicht funktionieren kann.

Zitat:

PaintBox1Paint
Die Paintbbox zeichnet nicht von alleine sondern erst dann wenn man sie auffordert das zu tun.
In deinem Beispiel versuchst du das zu erreichen indem du immer wieder (sehr schlechte Angewohnheit)
über Invalidate/Refresh diese anzustoßen damit sie deine Draw Methode ausführt.
Das führt umweigerlich dazu das diese flackert was man auch nicht vermeiden kann bei der verwendeten Methode.
Innerhalb onPaint eine Draw Funktion ausführen zu lassen ist also keine gute Idee wenn das Paint event
von dem gleichen Controll ausgelößt und ausgeführt werden soll.

Invalidate veranlasst die PaintBox fortwährend neu zu zeichnen was zu unsauberen Effekten führt.

Um dein problem zu beheben werf die procedure PaintBox1Paint raus.
Und lasse diese selbst zeichnen in dem du im Timer die Draw function

Delphi-Quellcode:
PaintBox1.Canvas.Draw(0, 0, Buffer);


vor

Delphi-Quellcode:
DrawSpectrum;


einfügst!
Deshalb davor weil ansonsten deine Abtastlinie nicht mehr gezeichnet wird.

Und schmeiß das Invalidate raus.

Eigentlich war das aber schon mit kleinen Einschränkungen von Medium beantwortet worden.
Zitat:

Zitat von Medium (Beitrag 1229417)
Flackern + TPaintbox = Es wird sehr wahrscheinlich nicht im OnPaint der Paintbox gezeichnet. Richtig wäre es daher im Timer (der kann praktisch nicht zu schnell sein)
nur das das Bitmap neu zu zeichnen, und dann TPaintbox.Invalidate aufzurufen.
Im TPaintbox.OnPaint Ereignis sollte dann das Bitmap auf den Paintbox-Canvas geblittet werden.
Das wäre auch unabhängig von Styles der saubere Weg.

Zitat:

Zitat von Medium (Beitrag 1229417)
Es wird sehr wahrscheinlich nicht im OnPaint der Paintbox gezeichnet

Kann auch nicht wenn er im OnPaint mit PaintBox1..Draw versucht diese zum zeichnen zu bewegen. (bzw. sich selbst aufzurufen)
Das geht nur von außerhalb bsp. über invalidate aber mit sehr schlechten ausgang wie man sieht.

gruss

TTF 26. Sep 2013 14:51

AW: Canvas flackern bei VCL Styles
 
Hallo EWeiss
Ich danke dir vielmals für deine Unterstützung. Ich werde mir merken, wie ich künftig mit PaintBoxes zu zeichnen habe.8-)
Liebe Grüsse
TTF


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