MSChart-Steuerelement ohne Flackern verwenden

Veröffentlicht: 16. Mrz 2006

Von Mathias Schiffer

Die Microsoft Newsgroups sind eine Quelle schier unerschöpflichen Wissens, das nahezu auf Knopfdruck abrufbar ist: Hunderte deutschsprachige Entwickler vom Einsteiger bis zum Profi treffen sich hier täglich virtuell, um Fragen zu stellen oder zu beantworten. Auch themennahe Probleme, Ansichten und Konzepte werden miteinander diskutiert. Sie kennen die Microsoft Newsgroups noch nicht?

Detaillierte Information für Ihre Teilnahme finden Sie auf der Homepage der Microsoft Support Newsgroups.

Diese Kolumne greift regelmäßig ein besonders interessantes oder häufig nachgefragtes Thema aus einer der Entwickler-Newsgroups auf und arbeitet es aus.

Auf dieser Seite

 Aus der Visual Basic Newsgroup microsoft.public.de.vb:
 Neuzeichnen unterbinden
 Neuzeichnen nur teilweise unterbinden
 Rundum-Sorglos-Lösung: Getrickst, aber einfach gut
 Der Autor

Aus der Visual Basic Newsgroup microsoft.public.de.vb:

Ich hab ein Problem mit dem MsChart-Steuerelement: Das dargestellte Diagramm wird mehrmals pro Sekunde aktualisiert und flackert dabei immer sehr stark. Ist das normal? Gibt es eine Möglichkeit, das zu verhindern?

Das MSChart-Steuerelement ist zwar ein besonders praktisches Steuerelement, aber in der Tat auch ein klassisches Sorgenkind, was das Flackern bei häufiger Aktualisierung seiner Inhalte angeht. Denn bei jeder Aktualisierung wird der gesamte Steuerelement-Inhalt neu gezeichnet – und das gilt selbst dann, wenn lediglich ein einziger Datenpunkt als neuer Pixel auftaucht. Bei solchem Vorgehen der Programmierer des Steuerelements ist ein Flackern bei häufiger Aktualisierung nahezu unvermeidlich.

Es gibt dennoch Wege, das Flackern zu reduzieren. In diesem Artikel finden Sie neben zwei problemorientierten Ansätzen abschließend sogar eine trickreiche Lösung, die das eigentlich unnötige Flackern gänzlich unterbindet.

 

Neuzeichnen unterbinden

In meinem Artikel „Flackern bei Bildschirmaktualisierungen verhindern“ finden Sie Hinweise darauf, wie Sie das Flackern von Steuerelementen allgemein verhindern können, indem Sie das Neuzeichnen von deren Inhalten zeitweise unterbinden.

Hieraus lässt sich eine Idee entwickeln: Lassen Sie die Anzeige des MSChart-Steuerelements etwa nicht bei jedem neuen Datenpunkt komplett neu zeichnen sondern z.B. nur nach jeweils 10 Datenpunkten, so entfallen neun von zehn Neuzeichenoperationen des gesamten Steuerelement-Inhalts. Das Flackern reduziert sich damit tatsächlich.

Nicht zu verleugnen ist der natürliche Nachteil dieser Methode: Der Graph wird nur entsprechend schrittweise aktualisiert dargestellt. Nicht für jede Anwendung ist eine solche Einschränkung hinnehmbar. Zudem: Reduziertes Flackern bleibt noch immer Flackern.

 

Neuzeichnen nur teilweise unterbinden

Im Artikel „Flackern bei Bildschirmaktualisierungen verhindern“ habe ich einen einfachen Deklarationstrick für das Eigengewächs RedrawWindowAny verwendet, um dem dort unnötigen Befüllen einer RECT-Struktur zu entgehen. Mithilfe des Deklarationstricks wurde schlicht die gesamte Fläche eines Fensters gesperrt. Ohne diesen Trick hätte ich die RECT-Struktur verwenden müssen. Infolge dessen hätte ich sie als Variable dimensionieren und für den gleichen Effekt mit den Maßen des jeweiligen Fensters vorab befüllen müssen, bevor ich die so befüllte Strukturvariable an die API-Funktion RedrawWindow hätte übergeben müssen.

In diesem formalen Mehraufwand liegt gleichzeitig eine Chance: Unterwerfen wir uns nämlich der RECT-Struktur, so müssen wir darin einen zu aktualisierenden Bildbereich beschreiben. Der orientiert sich als Rechteck-Koordinate an der linken oberen Ecke des betroffenen Fensters bzw. Steuerelements.

Dies ist dann nützlich, wenn der Bereich, in dem die nächsten zu zeichnenden Datenpunkte liegen werden, zweifelsfrei bekannt ist. Das kann etwa dann der Fall sein, wenn Funktionswerte über einer Achse aufgetragen werden: Bereits die Einschränkung des neu zu zeichnenden Bereichs auf diejenige vertikale Linie, auf der ein jeder sichtbarer Funktionswert für den Achsenwert erscheinen muss, führt zu einer flackerfreien Aktualisierung.

Auch diese Idee soll hier ohne konkreteres Beispiel bleiben (Sie finden alle notwendigen Elemente im zitierten Artikel). Denn einerseits ist die notwendige Funktionalität für API-erfahrene Entwickler nicht weiter kompliziert zu implementieren. Und andererseits möchte ich Sie gerne ohne Umwege direkt zum großen Finale führen, in dem uns solchermaßen feinsinnige Überlegungen zumindest für den Fall des MSChart-Steuerelements schlicht nicht mehr interessieren werden.

 

Rundum-Sorglos-Lösung: Getrickst, aber einfach gut

Wenn die vorherigen Lösungen für Sie nicht gangbar oder zu kompliziert waren, dann habe ich zum Abschluss noch die ideale Lösung für Sie: Machen Sie sich einfach keine Gedanken darüber, was genau im Bildbereich Ihres MSChart-Controls passiert!

Mit dem folgenden Vorgehen, das sich zur Anzeige des MSChart-Steuerelementinhalts trickreich eines zusätzlichen PictureBox-Steuerelements bedient, können Sie nämlich genau das tun:

  1. Platzieren Sie auf der Form, auf der sich Ihr MSChart-Steuerelement befindet, ein PictureBox-Steuerelement der gleichen Größe an der gleichen Position, so dass die beiden Controls deckungsgleich sind.

  2. Weisen Sie der Visible-Eigenschaft des MSChart-Steuerelements False zu (die Anzeige des Graphen wird im PictureBox-Steuerelement erfolgen).

  3. Weisen Sie der DrawMode-Eigenschaft des MSChart-Steuerelements den Wert VtChDrawModeBlit zu.

  4. Rufen Sie bei Datenaktualisierungen sowie aus Form_Paint (oder Usercontrol_Paint) der beherbergenden Form sowie aus MSChart_ChartUpdated und MSChart_DataUpdated heraus die im Folgenden dargelegte Routine UpdateMSChart auf und übergeben Sie dabei die Objektvariablen für das MSChart- sowie das PictureBox-Steuerelement.

  5. Definieren Sie in Ihrem Sourcecode die folgenden API-Prototypen sowie die im vorangegangenen Punkt angekündigte Methode UpdateMSChart:

Private Type RECT
  Left As Long
  Top As Long
  Right As Long
  Bottom As Long
End Type
  
Private Declare Function OleDraw _
  Lib "ole32.dll" ( _
  ByVal ptrUnknown As Object, _
  ByVal Aspect As Long, _
  ByVal hdcDraw As Long, _
  ByRef lprcBounds As RECT _
  ) As Long
  
  
Public Sub UpdateMSChart(ByVal MSChart As Control, ByVal MSChartCanvas As PictureBox)
' Überträgt den Steuerelementinhalt des übergebenen
' MSChart-Controls in das übergebene PictureBox-Control.
Dim rc As RECT
  
  ' Prüfung, ob MSChart-Control (typisierte Übergabe erzwingt Verweis)
  If TypeName(MSChart) = "MSChart" Then
  
    With MSChart
  
      ' Das MSChart-Steuerelement soll unsichtbar sein.
      ' Die Darstellung erfolgt im PictureBox-Control.
      If .Visible Then
        .Visible = False
      End If
  
      ' Auch die DrawMode-Eigenschaft wird hier geprüft.
      If .DrawMode <> VtChDrawModeBlit Then
        .DrawMode = VtChDrawModeBlit
      End If
  
      ' RECT-Struktur die Pixel-Fensterausmaße übergeben
      rc.Right = .Width / Screen.TwipsPerPixelX
      rc.Bottom = .Height / Screen.TwipsPerPixelY
  
      ' Das MSChart-Abbild an die Picturebox übertragen
      Call OleDraw(.Object, 1, MSChartCanvas.hDC, rc)
  
    End With
  
  End If
  
End Sub

Mit diesem PictureBox-Trick ist Ihr MSChart-Steuerelement garantiert flackerfrei und ruckelfrei!

 

Der Autor

Mathias Schiffer widmet sich als freier Softwareentwickler und Technologievermittler größeren Projekten ebenso wie arbeitserleichternden Alltagslösungen. Seit Jahren gibt er sein Wissen in unzähligen Publikationen und Beratungen auch an andere Entwickler und Entscheider weiter. Sie erreichen ihn per E-Mail an die Adresse Schiffer@mvps.org.