2017-07-16 1 views
0

J'essaie de faire une capture d'écran toutes les 10 millisecondes et de les définir comme Picturebox.image avec Timer. Pendant quelques secondes, le programme fonctionne parfaitement, mais après quelques secondes, le programme plante. J'ai essayé d'utiliser Dispose() Fonction à la fin du code pour effacer la mémoire, mais la fonction Dispose donne également une erreur. (Intervalle croissant de minuterie n'a pas travaillé)C# Fonction d'élimination donnant une erreur

using System; 
using System.Collections.Generic; 
using System.ComponentModel; 
using System.Data; 
using System.Drawing; 
using System.Linq; 
using System.Text; 
using System.Threading.Tasks; 
using System.Windows.Forms; 

namespace gameBot 
{ 
    public partial class Form1 : Form 
    { 
     public Form1() 
     { 
      InitializeComponent(); 
     } 
     public Bitmap screenshot; 
     Graphics GFX; 
     private void button1_Click(object sender, EventArgs e) 
     { 
      timer1.enabled = true; 
     } 

     private void timer1_Tick(object sender, EventArgs e) 
     { 
      takescreenshot(); 
     } 
     private void takescreenshot() 
     { 

      screenshot = new Bitmap(Screen.PrimaryScreen.Bounds.Width, 
      Screen.PrimaryScreen.Bounds.Height); 
      GFX = Graphics.FromImage(screenshot); 
      GFX.CopyFromScreen(Screen.PrimaryScreen.Bounds.X, Screen.PrimaryScreen.Bounds.Y, 0, 0, Screen.PrimaryScreen.Bounds.Size); 
      pictureBox1.Image = screenshot; 
      screenshot.Dispose();    
     }   
    } 
} 

L'erreur est

« Une exception non gérée du type 'System.ArgumentException' a eu lieu dans System.Drawing.dll

Informations supplémentaires: Le paramètre n'est pas valide. "

programme également utilise trop de RAM avant de s'écraser (Peut-être que cela se briser à cause de hors d'exception de mémoire?) As you can see in here

+1

quelle ligne renvoie l'exception? peut-être que l'intervalle est trop petit pour que le ramasse-miettes puisse le suivre. emballer les objets jetables dans «using», par exemple GFX devrait également être éliminé. faire un profil de mémoire, et voir si le cadre peut gérer avec un taux inférieur. [quelques messages existants] (https://stackoverflow.com/q/397754/1132334) – dlatikay

+0

Une capture d'écran bitmap de l'ensemble de votre écran, toutes les 10 millisecondes - soit 100 fois par seconde! - va manger beaucoup de mémoire à coup sûr. Si vous voulez faire cela, vous devrez vous assurer que tous les gros objets sont très éphémères et même alors, on peut se demander si votre garbage collector peut suivre. – oerkelens

Répondre

0

Voir Graphics.FromImage():

Vous devez toujours appeler la méthode Dispose pour libérer les graphiques et ressources connexes créées par la méthode FromImage.

De même, il n'est pas nécessaire de conserver ce graphique au niveau de la classe.

Avec cela à l'esprit, tout ce que vous avez besoin est:

public Bitmap screenshot; 

private void takescreenshot() 
{ 
    if (screenshot != null) 
    { 
     screenshot.Dispose(); 
    } 

    screenshot = new Bitmap(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height); 
    using (Graphics GFX = Graphics.FromImage(screenshot)) 
    { 
     GFX.CopyFromScreen(Screen.PrimaryScreen.Bounds.X, Screen.PrimaryScreen.Bounds.Y, 0, 0, Screen.PrimaryScreen.Bounds.Size); 
    } 
    pictureBox1.Image = screenshot; 
} 
1

je suggère de changer:

pictureBox1.Image = screenshot; 
screenshot.Dispose(); 

à:

var oldScreenshot = pictureBox1.Image; 
pictureBox1.Image = screenshot; 
GFX.Dispose(); 
if (oldScreenshot != null) 
    oldScreenshot.Dispose; 

pour vous assurer que l'ancienne capture d'écran est supprimée chaque fois que vous en affectez une nouvelle.

0

1) En fait, votre premier problème « Paramètre non valide. » C'est parce que vous disposez d'un objet capture d'écran. Si vous essayez d'exécuter votre méthode takescreenshot() une seule fois, vous obtiendrez cette erreur. Je suppose que cela se produit parce que vous définissez l'objet "capture d'écran" à PictureBox1.Image et que le jeter immédiatement. C'est logique! PictureBox ne peut pas rendre l'objet disposé.

2) Essayez de modifier votre code sur gestionnaire de bouton comme ça:

private Object thisLock = new Object(); 
    private void button1_Click(object sender, EventArgs e) 
    { 
     Thread thr = new Thread(() => 
     { 
      while (true) 
      {pictureBox1.Invoke((Action)(() => 
        { 
         screenshot = new Bitmap(Screen.PrimaryScreen.Bounds.Width, 
          Screen.PrimaryScreen.Bounds.Height); 
         GFX = Graphics.FromImage(screenshot); 
         GFX.CopyFromScreen(Screen.PrimaryScreen.Bounds.X, Screen.PrimaryScreen.Bounds.Y, 0, 0, 
          Screen.PrimaryScreen.Bounds.Size); 
         pictureBox1.Image = screenshot; 
        })); 
       } 
       Thread.Sleep(10); 
     }); 
     thr.Start(); 
    } 

fonctionne très bien! Le meilleur moyen est d'obtenir un événement lorsque le rendu de la boîte à images est terminé, mais je n'ai rien trouvé à ce sujet.