Domanda

Usando C ++ e .net ho un flusso di dati che voglio visualizzare come immagine a scorrimento. Ogni volta che ricevo alcuni nuovi dati, voglio aggiungerli come nuova riga (128x1 pixel) e scorrere i contenuti precedenti da un lato.

La mia prima pugnalata al problema riguardava il rendering dell'intero set di dati ogni volta che ottenevo una nuova riga. Funzionava, ma era troppo lento, quindi sto pensando che avrebbe più senso scrivere su un buffer di qualche tipo (forse una bitmap?). Il problema è che non riesco a vedere come posso farlo; Gli oggetti Graphic ti consentono di disegnare abbastanza felicemente, ma non riesco a vedere un modo ovvio per dire al mio controllo di usare un oggetto Bitmap come buffer? Allo stesso modo, non riesco a vedere un modo per disegnare su una bitmap che potrei quindi scrivere sullo schermo.

Questo deve essere possibile, ma finora il mio google-foo mi ha deluso ...

[Modifica1] Giusto per chiarire, i dati sono uno spettrogramma. L'immagine seguente mostra il tipo di cosa che stavo cercando di ottenere:

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

I dati che sto tramando arrivano in array di float. Non c'è nulla che limiti quanti ne otterrò, quindi voglio solo dimenticare i dati che cadono dal lato della trama.

Attualmente sto ereditando da un System::Windows::Forms::UserControl , ma potrei passare a qualcos'altro se c'è un'alternativa migliore?

È stato utile?

Soluzione

Dai un'occhiata alla ScrollWindow win32 metodo. È possibile scorrere i dati esistenti sullo schermo e quindi disegnare solo i nuovi dati. Questo è molto veloce.

Altri suggerimenti

Bitmap bmpImage = new Bitmap (512.512);

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

{

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

}

(Immagine) bmpImage.save ()

Una possibile strategia:

  • Disegna su un backbuffer da sinistra a destra che si avvolge quando raggiunge la fine. Esegui la logica di scorrimento solo quando dipingi sullo schermo (con un framerate specificato). Usa DrawImage con rettangolo di origine e rettangolo di destinazione per raggiungere questo obiettivo.

  • Usa il metodo bitmap.LockBits (...) e bitmap.UnlockBits (...) per modificare i dati Bitmap non elaborati. Fare attenzione a bloccare solo il rettangolo che si intende modificare, poiché queste funzioni eseguono effettivamente copie dei dati bitmap dalla memoria non gestita alla memoria gestita. Un esempio di come eseguire questa operazione è descritto qui Metodo Bitmap .. ::. LockBits (Rectangle, ImageLockMode, PixelFormat) .

  • Un'alternativa a LockBits è usare SetPixel sulla bitmap. Ma SetPixel è noto per essere lento.

  • Quando si uniscono le immagini allo schermo, assicurarsi che CompositingMode sull'istanza Graphics sia impostato su bmpg.CompositingMode = CompositingMode.SourceCopy e che il formato pixel del buffer posteriore sia PixelFormat.Format32bppPArgb.

Non sono del tutto chiaro su cosa stai tentando di disegnare (una sorta di controllo in una finestra di dialogo?) ma a quanto si suppone dovrebbe funzionare qualcosa del tipo:

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, ...);
}

Questa è comunque un'ipotesi molto approssimativa. La chiamata DrawItem potrebbe apparire molto diversa se si utilizza .NET (non ho familiarità con esso ...), ma la logica di base dovrebbe essere approssimativamente la stessa.

A seconda di quali siano esattamente i tuoi dati, potrebbe non essere efficiente disegnare righe di 1 pixel alla volta. Potrebbe essere meglio disegnare un'area estesa e mostrarne solo alcune parti come richiesto, anche se ciò dipenderà ovviamente dal modo in cui arrivano i dati.

Potrebbe anche essere necessario eseguire una sorta di aggiornamento della bitmap su " scroll " il suo contenuto. Lo lascio a te :-)

Prova quanto segue:

  • Avvia una nuova applicazione VC ++ WinForms.
  • Aggiungi un controllo utente denominato "Spettrogramma" al progetto
  • Aggiungi un controllo timer al controllo utente 'Spectrogram' e imposta la proprietà 'Enabled' su true
  • Aggiungi le seguenti variabili private al controllo utente "Spettrogramma"
private:
Graphics ^m_gfxBuffer;
Graphics ^m_gfxOriginal;
Bitmap ^m_bmpBuffer;
Bitmap ^m_bmpOriginal;
  • Aggiungi il seguente codice al costruttore 'Spectrogram':

m_bmpBuffer = gcnew Bitmap(this->ClientSize.Width, this->ClientSize.Height);
m_gfxBuffer = Graphics::FromImage(m_bmpBuffer);
m_bmpOriginal = gcnew Bitmap(this->ClientSize.Width, this->ClientSize.Height);
m_gfxOriginal = Graphics::FromImage(m_bmpOriginal);
this->SetStyle(::ControlStyles::AllPaintingInWmPaint | ::ControlStyles::DoubleBuffer | ::ControlStyles::UserPaint | ::ControlStyles::OptimizedDoubleBuffer, true);
this->UpdateStyles();
  • Aggiungi il seguente codice all'evento paint 'Spectrogram':

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);    
  • Aggiungi il seguente codice l'evento tick 'Spectrogram' timer

this->Invalidate(false);
  • Salva il tuo progetto
  • Pulisci e ricostruisci
  • Esegui il progetto
  • Chiudi il modulo in esecuzione
  • Il controllo utente di Spectrogram ora dovrebbe essere nella 'Casella degli strumenti'
  • Trascinalo dalla 'Casella degli strumenti' al modulo e dovresti vedere una specie di spettro colorato casuale a scorrimento.

Questo dovrebbe darti un'idea generale di un controllo buffer bitmap. La chiave qui è & Quot; SetStyle & Quot; chiama il costruttore e l'offset della bitmap di -1 nell'evento paint.

Dovrai smaltire correttamente gli oggetti grafici e bitmap e gestire la loro distruzione e ricostruzione nell'evento di ridimensionamento.

Spero che questo aiuti. Fammi sapere come va.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top