2010-03-15 5 views
2

Je fais un peu de graphique via le System.Drawing et j'ai quelques problèmes.Trois méthodes System.Drawing manifestent un dessin lent ou un flickery: Solutions? ou d'autres options?

Je maintenir des données dans une file d'attente et je suis dessin (graphique) que les données sur trois blocs d'image

cette méthode remplit le bloc d'image défile ensuite à travers le graphe.

afin de ne pas dessiner sur les dessins précédents (et semblant plus en désordre) j'ai trouvé 2 solutions pour dessiner le graphique.

  1. Appel plot.Clear(BACKGOUNDCOLOR) avant que la boucle de tirage [bloc commenté]

bien que cela provoque un scintillement à apparaître à partir du temps qu'il faut pour faire la boucle de dessin réelle.

  1. appel plot.DrawLine(channelPen[5], j, 140, j, 0); juste avant chaque DrawLine [a commenté]

bien que cela provoque le dessin pour commencer ok alors ralentir très rapidement à une exploration comme si une commande d'attente avait été placé avant la commande draw.

Voici le code de référence:

/*plotx.Clear(BACKGOUNDCOLOR) 

ploty.Clear(BACKGOUNDCOLOR) 

plotz.Clear(BACKGOUNDCOLOR)*/ 

for (int j = 1; j < 599; j++) 
      { 
       if (j > RealTimeBuffer.Count - 1) break; 

       QueueEntity past = RealTimeBuffer.ElementAt(j - 1); 
       QueueEntity current = RealTimeBuffer.ElementAt(j); 

       if (j == 1) 
       { 
        //plotx.DrawLine(channelPen[5], 0, 140, 0, 0); 
        //ploty.DrawLine(channelPen[5], 0, 140, 0, 0); 
        //plotz.DrawLine(channelPen[5], 0, 140, 0, 0); 
       } 

       //plotx.DrawLine(channelPen[5], j, 140, j, 0); 
       plotx.DrawLine(channelPen[0], j - 1, (((past.accdata.X - 0x7FFF)/256) + 64), j, (((current.accdata.X - 0x7FFF)/256) + 64)); 

       //ploty.DrawLine(channelPen[5], j, 140, j, 0); 
       ploty.DrawLine(channelPen[1], j - 1, (((past.accdata.Y - 0x7FFF)/256) + 64), j, (((current.accdata.Y - 0x7FFF)/256) + 64)); 

       //plotz.DrawLine(markerPen, j, 140, j, 0); 
       plotz.DrawLine(channelPen[2], j - 1, (((past.accdata.Z - 0x7FFF)/256) + 94), j, (((current.accdata.Z - 0x7FFF)/256) + 94)); 


      } 

est-il des astuces pour éviter ces frais généraux?

Sinon, y aurait-il d'autres/meilleures solutions?

EDIT: Voir [Solution finale] ci-dessous pour le code de la solution

Répondre

4

PictureBox a déjà une double mémoire tampon activée. La seule façon de percevoir le scintillement est lorsque vous dessinez directement sur l'écran au lieu d'utiliser l'événement Paint. Il n'est pas clair si vous faites de votre extrait. Vous mettre en mémoire tampon avec un bitmap fonctionnerait également mais n'est pas aussi efficace que la double mise en mémoire tampon implémentée par Windows Forms.

Appelez sa méthode Invalidate() lorsque les données changent, faites le dessin dans l'événement Paint (en utilisant e.Graphics) et il ne clignotera pas.

+1

Cela fonctionne un régal, merci –

+0

Cela a fonctionné pour moi 2. Dessiner avec l'objet graphique créé avec 'this.CreateGraphics()' a causé la propriété 'DoubleBuffered' pour ne pas fonctionner .. Ce problème causé ** scintillement ** et la définition de la propriété 'DoubleBuffered' a provoqué l'abandon de BLANK. Mais dessiner avec un objet graphique créé par ** peintures ** 'e.Graphics' a résolu tous ces problèmes! Merci beaucoup Hans! – Anirudha

1

Essayez tamponner vos données à un autre bitmap avant de le mettre dans la zone d'image. Cela permettra d'éliminer le scintillement.

Par exemple:

// create this once for each graph 
Bitmap buffer = new Bitmap({width}, {height}); 

// when the data changes 
using (Graphics g = Graphics.FromImage(buffer)) 
{ 
    // ... draw using the graphics 
} 

// draw the buffer on the picture box's image 

que tu fais le dessin sur un thread séparé? Combien de fois dessinez-vous les données une seconde? Votre programme se sentira lent si vous le faites sur le thread principal ou dessinez plusieurs fois le bitmap entier un certain nombre de fois par seconde.

+0

Merci pour la réponse rapide et le montage des conseils. J'ai réussi à faire fonctionner la mémoire tampon bitmap et elle est fluide si je ne fais tourner qu'un seul graphique mais scintille avec plus. L'intervalle entre le premier et le deuxième appel a été chronométré à 14 ms. A la minute où le dessin est fait sur le fil GUI mais sur votre conseil je vais le déplacer –

+0

J'ai aussi essayé de dessiner les données pour les 3 graphes dans l'un (toujours en utilisant le tampon bitmap) Cela provoque aussi des scintillements comme au début. –

+0

@Luke: Traitez-vous l'événement Paint/OnPaint ou la propriété ImageBox de l'image? –

0

Je voudrais utiliser une approche de double tampon. Créer un nouveau bitmap en mémoire (la même taille que le graphique) crée un objet graphique de ce bitmap.

Ensuite, dessinez ce que vous voulez sur cet objet.

Une fois le dessin terminé, créez un autre objet graphique à partir de PictureBox et dessinez le bitmap en mémoire à l'aide de DrawImage.

Ceci devrait réduire le scintillement puisque vous dessinez tout de l'écran excepté un grand tirage qui met à jour toute l'image.

Espérons que ça aide.

+0

Comme je l'ai mentionné à Zach, j'ai réussi à faire fonctionner le tampon bitmap et il est lisse si je ne fais tourner qu'un graphique mais scintille avec plus. –

0

Sous-classez votre bloc d'image et activez l'option double tampon.

Classe publique MyBufferedPictureBox Hérite System.Windows.Forms.PictureBox

Public Sub New() 
    MyBase.New() 

    Me.SetStyle(ControlStyles.OptimizedDoubleBuffer, True) 
End Sub 

End Class

http://msdn.microsoft.com/en-us/library/system.windows.forms.control.setstyle.aspx

+1

Je n'ai pas eu beaucoup de succès en utilisant ce drapeau. Si je me souviens bien, la plupart des contrôles sont déjà doublés par défaut. Ce serait très bien si cela fonctionnait, cependant. –

0

[SOLUTION FINALE]

Utilisation de l'événement de peinture même avec des boucles en double a été assez vite! Dans la fin, plutôt que de dupliquer la boucle de dessin dans chaque événement, j'ai utilisé le premier événement pour dessiner les deux autres graphes sur des bitmaps, puis sur leur événement paint, dessiner simplement le bitmap.

Donc essentiellement la solution finale était une combinaison de plusieurs de vos réponses.

Merci les gars.

private void pictureBoxAccX_Paint(object sender, PaintEventArgs e) 
     { 
      bufferedploty.Clear(Color.Black); 
      bufferedplotz.Clear(Color.Black);   

      for (int j = 1; j < 599; j++) 
      { 
       if (j > RealTimeBuffer.Count - 1) break; 

       QueueEntity past = RealTimeBuffer.ElementAt(j - 1); 
       QueueEntity current = RealTimeBuffer.ElementAt(j); 

       e.Graphics.DrawLine(channelPen[0], j - 1, (((past.accdata.X - 0x7FFF)/256) + 64), j, (((current.accdata.X - 0x7FFF)/256) + 64)); 
       bufferedploty.DrawLine(channelPen[1], j - 1, (((past.accdata.Y - 0x7FFF)/256) + 64), j, (((current.accdata.Y - 0x7FFF)/256) + 64)); 
       bufferedplotz.DrawLine(channelPen[2], j - 1, (((past.accdata.Z - 0x7FFF)/256) + 94), j, (((current.accdata.Z - 0x7FFF)/256) + 94)); 
      } 
     } 


     private void pictureBoxAccY_Paint(object sender, PaintEventArgs e) 
     {   
      e.Graphics.DrawImage(BufferedBitMapy, new Point(0, 0));    
     } 


     private void pictureBoxAccZ_Paint(object sender, PaintEventArgs e) 
     {    
      e.Graphics.DrawImage(BufferedBitMapz, new Point(0, 0)); 
     } 




private void AddAccPoints() 
     { 
      //Code for putting in New queue data Here... 
      pictureBoxAccX.Invalidate(); 
      pictureBoxAccY.Invalidate(); 
      pictureBoxAccZ.Invalidate(); 
     } 

EDIT: Avec cette solution exacte invalidant les commandes peut provoquer la planification des événements comme indéfini et arrêter au hasard le dessin comme la création d'images est réalisée dans une des méthodes d'événement.

Voir ici: Onpaint events (invalidated) changing execution order after a period normal operation (runtime)