2009-06-28 4 views
1

Mit C++ und .net habe ich einen Strom von Daten, die ich als Bildlauf anzeigen möchte. Jedes Mal, wenn ich neue Daten erhalte, möchte ich sie als neue Zeile (128x1 Pixel) hinzufügen und den vorherigen Inhalt auf eine Seite scrollen.Wie schreibe ich in einen (Bitmap?) Image Buffer für schnellere GDI + Displays?

Mein erster Stich bei dem Problem umfasste das Rendern des gesamten Datensatzes jedes Mal, wenn ich eine neue Zeile bekam. Das hat funktioniert, war aber viel zu langsam, also denke ich, dass es sinnvoller wäre, in einen Puffer zu schreiben (eine Bitmap vielleicht?). Das Problem ist, dass ich nicht sehen kann, wie ich das tun kann; Graphic Objekte können Sie ganz glücklich zeichnen, aber ich kann keinen offensichtlichen Weg sehen, meine Kontrolle zu einem Bitmap Objekt als Puffer verwenden? Ebenso kann ich keine Möglichkeit sehen, auf eine Bitmap zu zeichnen, die ich dann auf den Bildschirm schreiben könnte.

Dies muss möglich sein, aber mein Google-foo hat mir bisher versagt ...

[Edit1] Nur um zu klären, sind die Daten ein Spektrogramm. Die folgende Abbildung zeigt die Art von Sache, die ich habe versucht zu erreichen:

alt text http://www.geekops.co.uk/photos/0000-00-02%20(Forum%20images)/ScrollingGraphicsAlgorithmExplanation.png

Die Daten Ich bin kommt in Arrays von Schwimmern Plotten. Es gibt nichts zu begrenzen, wie viele ich bekomme, also möchte ich nur Daten vergessen, wie es von der Seite der Handlung abfällt.

Ich erben derzeit von einem System::Windows::Forms::UserControl, aber könnte zu etwas anderem wechseln, wenn es eine bessere Alternative gibt?

Antwort

5

Werfen Sie einen Blick auf die Win32-Methode ScrollWindow. Sie können die vorhandenen Daten auf dem Bildschirm scrollen und dann nur die neuen Daten zeichnen. Dies ist sehr schnell.

+0

Bedeutet das, dass das Bild jedes Mal wachsen muss, wenn ich neue Daten hinzufüge? –

+0

Nein ... das ScrollWindow macht genau das, was Sie wollen. Es scrollt den vorhandenen Inhalt innerhalb eines Clipping-Bereichs - zum Beispiel das CPU-Diagramm im Task-Manager. –

+0

Das klingt wie eine nette wy, was ich will, aber meine System :: Windows :: Forms :: UserControl abgeleitete Klasse scheint keine ScrollWindow-Funktion zu haben. Muss ich eine Bildlaufleiste hinzufügen oder eine andere Basisklasse verwenden? –

0

ich genau nicht ganz klar bin, was Sie versuchen (auf einem Dialog eine Art von Kontrolle?) Zu zeichnen, aber bei einer Vermutung sollte es so etwas wie arbeiten:

class Foo { 
    ... 
    Gdiplus::Bitmap* m_pBitmap; 
}; 

void Foo::DrawItem(LPDRAWITEMSTRUCT lpDraw) { 

    // update bitmap if needed 
    if(some_condition_requiring_bitmap_redraw) { 

     // do expensive drawing into bitmap 
     Gdiplus::Graphics graphics(m_pBitmap); 
    } 


    // create a graphics object to draw the control from the bitmap 
    Gdiplus::Graphics graphics(lpDraw->hDC); 
    graphics.DrawImage(m_pBitmap, ...); 
} 

, die ein sehr rau schätze es trotzdem. Der DrawItem-Aufruf sieht möglicherweise anders aus, wenn Sie .NET verwenden (ich bin nicht damit vertraut ...), aber die grundlegende Logik sollte ungefähr gleich sein.

Je nachdem, was genau Ihre Daten sind, ist es möglicherweise nicht effizient, jeweils 1 Pixelzeile zu zeichnen. Sie können besser einen großen Bereich zeichnen und zeigen nur Teile davon wie erforderlich - obwohl das hängt natürlich davon ab, wie Ihre Daten kommt.

Sie müssen möglicherweise auch eine Art von Aktualisierung zu Ihrem Bitmap "scrollen" "Sein Inhalt. Ich werde das :-)

Ihnen überlassen
+0

Ja, dies ist ein benutzerdefiniertes Steuerelement in einem Dialogfeld. –

0

Versuchen Sie Folgendes:

  • Starten Sie eine neue VC++ WinForms-Anwendung.
  • eine Benutzersteuerung namens ‚Spektrogramm‘ zum Projekt
  • hinzufügen Timer-Steuerung auf das ‚Spektrogramm‘ Benutzersteuerung hinzufügen und die ‚Aktiviert‘ Eigenschaft auf true
  • Fügen Sie die folgenden privaten Variablen auf das ‚Spektrogramm‘ gesetzt Benutzersteuerung
private: 
Graphics ^m_gfxBuffer; 
Graphics ^m_gfxOriginal; 
Bitmap ^m_bmpBuffer; 
Bitmap ^m_bmpOriginal; 
  • Fügen Sie den folgenden Code in das 'Spektrogramm' Baumeister:
  • Fügen Sie den folgenden Code in das Paint-Ereignis 'Spektrogramm':

array<unsigned char, 1> ^bytes = gcnew array<unsigned char, 1>(m_bmpBuffer->Height * 3); 
Random ^r = gcnew Random(); 
r->NextBytes(bytes); 

m_gfxOriginal->DrawImage(m_bmpBuffer, -1, 0); 

int y = 0; 
for (int i = 0; i < m_bmpOriginal->Height * 3; i += 3) 
{ 
    m_bmpOriginal->SetPixel(m_bmpOriginal->Width - 1, y++, ::Drawing::Color::FromArgb(255, bytes[i], bytes[i + 1], bytes[i + 2])); 
} 

m_gfxBuffer->DrawImage(m_bmpOriginal, 0, 0); 
e->Graphics->DrawImage(m_bmpOriginal, 0, 0);  
  • Fügen Sie den folgenden Code der 'Spektrogramm' Timer Tick-Ereignis

this->Invalidate(false); 
  • Speichern Sie Ihr Projekt
  • reinigen und neu erstellen
  • Führen Sie das Projekt
  • den Lauf Formular schließen
  • Spektrogramm Benutzersteuerung jetzt von dem ‚Toolbox‘
  • Ziehen Sie es das Formular und Sie sollen in der ‚Toolbox‘ sein sollte, sehen Sie ein scrollendes zufälliges farbiges Spektrogramm von Arten.

Dies sollte Ihnen eine allgemeine Vorstellung von einem Bitmap-gepufferten Steuerelement geben. Der Schlüssel hier ist der Aufruf "SetStyle" im Konstruktor und der Offset der Bitmap um -1 im Paint-Ereignis.

Sie müssen die Grafiken und Bitmap-Objekte ordnungsgemäß entsorgen und sie im Resize-Event zerstören und neu erstellen.

Hoffe, das hilft. Lass mich wissen wie es geht.

1

Bitmap bmpImage = neues Bitmap (512,512);

for (int iRow = 0; iRow < 512; iRow ++)

{

for (int iCol = 0; iCol <512; iCol++) 
         { 
          Color clr; 
          bmpImage.SetPixel(iCol, iRow, clr); 
         } 

}

(Image) bmpImage.save()

1

Eine mögliche Strategie:

  • Zeichnen Sie von links nach rechts einen Backbuffer, der sich beim Erreichen des Endes umschlingt. Führen Sie die Bildlauflogik nur beim Malen auf Bildschirm aus (bei einer bestimmten Bildrate). Verwenden Sie DrawImage mit Quellrechteck und Zielrechteck, um dies zu erreichen.

  • Verwenden Sie bitmap.LockBits (...) und Bitmap.UnlockBits (...) Methode zum Ändern der Rohbitmap-Daten. Achten Sie darauf, nur das Rechteck zu sperren, das Sie ändern möchten, da diese Funktionen tatsächlich Kopien der Bitmap-Daten von nicht verwaltetem zu verwaltetem Speicher erstellen. Ein Beispiel dafür ist hier beschrieben Bitmap..::.LockBits Method (Rectangle, ImageLockMode, PixelFormat).

  • Eine Alternative zu LockBits ist die Verwendung von SetPixel in der Bitmap. Aber SetPixel ist dafür bekannt, langsam zu sein.

  • Stellen Sie beim Blitting von Bildern auf dem Bildschirm sicher, dass die CompositingMode on Graphics-Instanz auf bmpg.CompositingMode = CompositingMode.SourceCopy gesetzt ist und PixelFormat.Format32bppPArgb das Pixelformat des Hintergrundpuffers ist.
Verwandte Themen