Ausgewählte Artikel zur Programmierung mit Delphi

Werner Voigt

 für 


Genug geflackert - Bildschirmflackern vermeiden

Autor: Dipl.-Math. Werner Voigt

veröffentlicht in Toolbox 6/2002 Seite 68/69
Copyright 2002 © Werner Voigt und Toolbox
Bitte beachten Sie auch die Hinweise zur kommerziellen Nutzung

Problem:

Rasche Änderungen von Bildinhalten einer Paintbox oder einer Image-Komponente führen leicht zu unerfreulichen Flackererscheinungen (siehe Leserfrage von Matthias Walter in Toolbox 5/2002). Dagegen suchen wir eine wirksame Strategie.

Dazu erinnern wir uns an die Zeit vor Windows. Unter DOS war die Grafikprogrammierung für den Programmierer ein hartes Brot. Nicht nur bei raschen Bildänderungen war direkter Kontakt mit der Hardware (Grafikkarte und Monitor) sehr zweckdienlich. Zwei Dinge waren wichtig:

  1. Bildänderungen sollten nur während des Strahlrücklaufs (wenn der Bildschirm also noch nachleuchtet) durchgeführt werden.
  2. Idealerweise wird dabei ein bereits vorgefertigtes Bild mit einem Schlag ins Spiel gebracht.

Dann blieb allerdings immer noch der Unsicherheitsfaktor einer unbekannten Grafikkarte, deren Eigenheiten stören konnten, oder deren Bildspeicher zu klein war.
Unter Windows sind unsere Partner die Methoden von TCanvas, hinter denen Windows-API-Aufrufe und die Treiberroutinen der Grafikkarte stecken. Wir vertrauen darauf, daß dadurch schon mit der Hardware optimal zusammengearbeitet wird und hier für uns nichts mehr zu holen ist. Sonst riskieren wir nur, ein Programm zu erstellen, welches nicht auf jedem Ziel-PC vernünftig läuft.
Damit bleibt uns noch die Möglichkeit, mit möglichst wenigen sichtbaren Zeichenaktionen das Bild zu erstellen.
Die Lösung scheint in einer Canvas zu liegen, die quasi als Entwurfszeichenfläche im Dunkeln alle unsere Zeichenaktionen über sich ergehen läßt. Das jeweilige Resultat sollte dann in einem einzigen Programmschritt in eine sichtbare Komponente transportiert werden. Mit dem Hintergedanken an einen eventuell folgenden Druckschritt (und damit der Notwendigkeit der Skalierbarkeit) bietet sich natürlich ein Metafilecanvas an. Das ist aber ein Irrweg. In einem Metafile werden nur Canvas-Methodenaufrufe codiert, die beim Zeichnen der Datei einfach Schritt für Schritt ausgeführt werden. Deshalb favorisiere ich eine Bitmap mit den Eigenschaften des Zielbereichs auf dem Bildschirm. Erst wird in die Bitmap-Canvas gezeichnet und wenn alles im Kasten ist, reicht ein Draw-Aufruf für die Bildgebung.
Weiterhin ist zu bedenken, das Windows sich möglichst wenig in unsere Arbeit einmischen sollte. So ist ein Löschen des Hintergrundes einer Paintbox- oder Image-Komponente bei uns besser aufgehoben. Deshalb könnte es nützlich sein, wm_EraseBkg-Botschaften abzufangen, oder Invalidate-Anweisungen (die ja auch eben diese Botschaft provozieren) zu vermeiden. Der Preis dafür ist relativ gering, denn man muß sich ja nur bei Neudarstellungen des Fensters selber kümmern (OnResize & Co).
Für die normale Nutzung genügt es aber, die Darstellungsroutine in onPaint aufzurufen.

Als Ziel kommen also eine Paintbox, ein Image oder aber auch das Form selbst infrage.
Um zu einem abschließenden Urteil zu kommen, benötigen wir ein Programm, welches verschiedene Realisierungen der gleichen Aufgabe zu Vergleichszwecken anbietet.
Die Aufgabe sollte schon etwas aufwendig sein. In möglichst schneller Folge ist ein Bild darzustellen. Es sollen mehrere Bildelemente übereinander gelegt werden. Bei ungeschickter Programmierung gibt das ein hübsches Geflacker. Aber wir wollen eine (wenn möglich) perfekte Vorstellung.

Zur Realisierung

Auf ein Form ziehen wir ein Label, dessen Caption leer bleibt. Wir setzen Autosize auf "false" und ziehen das Rechteck auf die für unsere Grafik gewünschte Größe. Dieses Rechteck ist der Ausgangspunkt für unsere Testkandidaten. Wir benötigen außerdem eine Radiogroup zur Auswahl und Eingabefelder zur Variation der Testaufgabe.
Mit dem Testbutton wird das Bild in einer Schleife gezeichnet. Dabei wird es jeweils vollständig neu erzeugt. Um diesen Vorgäng zu verdeutlichen, wird eine simple Animation realisiert. In Abhängigkeit von der Radiobox wird das passende Anzeigeobjekt ausgewählt/erzeugt und am Ende der Schleife wieder entlassen.
In Form.Create wird das Bitmap für die Arbeit im Hintergrund erzeugt. Damit existiert es während der gesamten Programmlaufzeit und wir vermeiden ständige Speicheranforderungen/-freigaben.

  Dark := TBitmap.Create;
  Dark.Height := Label1.Height;
  Dark.Width := Label1.Width;
  

Die eigentliche Testschleife ist nicht allzu spektakulär. Nach dem Ezeugen des gewählten Anzeigeobjekts wird immer wieder in einer case-Anweisung ImagePaint mit der jeweiligen Ziel-Canvas aufgerufen. Die Variable Test ist nur für einen vorzeitigen Schluß der Testschleife via TestStopBtn zuständig.

if Test
then begin
  case RadioGroup1.ItemIndex of
  0: ImagePaint(PB.Canvas);      // PaintBox direkt
  1: begin // PaintBox mit "Vorzeichnung" im Bitmap
      ImagePaint(Dark.Canvas);
      PB.Canvas.Draw(0,0,Dark);
     end;
  2: ImagePaint(IMG.Canvas);     // Image direkt
  3: begin // Image mit "Vorzeichnung" im Bitmap
       ImagePaint(Dark.Canvas);
       IMG.Canvas.Draw(0,0,Dark);
     end;
  4: begin // Form mit "Vorzeichnung"  im Bitmap
       ImagePaint(Dark.Canvas);
       Form1.Canvas.Draw(Label1.Left,Label1.Top,Dark);
     end;
  end; {case}
...
  

In der Schleife befindet sich noch eine Bremse, um die "Animationsgeschwindigkeit" über ein SpinEdit einzustellen. Damit lassen sich Zusammenhänge mit der Anzeigefrequenz besser untersuchen. Lebenswichtig ist der Aufruf von Application.ProcessMessages, sonst kommt TestStopBtnClick nicht zum Zug.
In ImagePaint erfolgt das eigentliche Zeichnen des Bildes. Damit ist die Chancengleichheit aller Testkandidaten gesichert. Es geht um die mehr oder weniger gelungene Darstellung eines Augenaufschlags.

Fazit

Sowohl mit Delphi 4, 5 und 6 als auch mit unterschiedlichen PC's und Monitoren (TFT und klassischer Bildschirm) habe ich unter Windows 98, Me und 2000 das gleiche Ergebnis erzielt. Die Paintbox erweist sich als nicht hoch belastbar. Auch das Image ist nicht in allen Versionen richtig überzeugend. Während mit einem Bitmap im Hintergrund die Paintbox (wie auch das Form selbst) immer ein perfektes Bild liefert, ist dem Image mit Delphi 6 (im Gegensatz zu den Vorgängerversionen!) nicht so recht zu helfen. Warum das so ist, konnte ich bisher nicht ergründen.
Das Ergebnis legt den Verdacht nahe, daß z.B. in Visual Basic 6 vorhandene Anzeigeelemente u.U. auf andere Weise als Paintbox und Image arbeiten.
Hinweis: Die Quellen für Delphi 6 sind in Blink6.dpr (UBlink.pas) und für Delphi 4 oder 5 in Blink4.dpr (unit1.pas) zu finden.

Copyright © 2003 by  EDVoigt  (Werner Voigt).