2016-07-21 8 views
0

Ich schreibe eine einfache App mit C#, .Net 4.5 und Gtk #, die einen Teil des Bildschirms erfasst und auf ein Bild lädt in einem Fenster. Nach ein paar Sekunden verschwindet das Bild und ich bekomme den folgenden Fehler:Aktualisieren eines Bildes in einem Gtk # -Fenster, nach einer gewissen Zeit verschwindet das Bild

Glib-CRITICAL **: Quell-ID xxxx wurde nicht gefunden, wenn versucht wird, es zu entfernen.

Relevante Code:

Program.cs:

using System.Windows.Forms; 

namespace Dota2Trainer 
{ 
    class MainClass 
    { 
     public static void Main(string[] args) 
     { 
      Gtk.Application.Init(); 
      MiniMapOverlay myWin = new MiniMapOverlay(); 
      myWin.KeepAbove = true; 
      //myWin.Decorated = false; 
      myWin.Resize(200, 200); 
      myWin.ShowAll(); 
      ScreenCapturer screenCap = new ScreenCapturer(30, Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height, myWin); 
      screenCap.Start(); 
      Gtk.Application.Run(); 
     } 
    } 
} 

MiniMapOverlay.cs:

using System; 
using System.Drawing; 
using System.IO; 
using System.Timers; 
using Gtk; 

namespace Dota2Trainer 
{ 
    public partial class MiniMapOverlay : Gtk.Window 
    { 
     Gtk.Image image = null; 
     public MiniMapOverlay() : base(Gtk.WindowType.Toplevel) 
     { 
      image = new Gtk.Image(); 
      var buffer = System.IO.File.ReadAllBytes(".\\image0.jpeg"); 
      var pixbuf = new Gdk.Pixbuf(buffer); 
      image.Pixbuf = pixbuf; 
      this.Add(image); 
      this.Build(); 
     } 

     public void RefreshImage(byte[] buffer) 
     { 
      try 
      { 
       var pixbuf = new Gdk.Pixbuf(buffer); 
       image.Pixbuf = pixbuf; 
      } 
      catch (Exception exception) 
      { 
       Console.WriteLine(exception.Message); 
      } 
     } 
    } 
} 

ScreenCapturer.cs:

using System; 
using System.Drawing; 
using System.Drawing.Imaging; 
using System.IO; 
using System.Timers; 

namespace Dota2Trainer 
{ 
    public delegate void OnSavedImage(byte[] screenCap); 
    public class ScreenCapturer 
    { 
     public System.Timers.Timer aTimer; 
     int interval= 30000; 
     readonly int screenWidth; 
     readonly int screenHeight; 
     Rectangle bounds; 
     const double miniMapWidthPercentage = 0.15; 
     const double miniMapHeightPercentage = 0.25; 
     Bitmap bitmap; 
     bool Busy = false; 
     ImageConverter converter = new ImageConverter(); 
     public OnSavedImage onSaveImage; 

     public ScreenCapturer(int interval, int screenWidth, int screenHeight, MiniMapOverlay imageHolder) 
     { 
      this.screenHeight = screenHeight; 
      this.screenWidth = screenWidth; 
      this.interval = interval; 
      aTimer = new System.Timers.Timer(); 
      aTimer.Elapsed += new ElapsedEventHandler(OnTimedEvent); 
      aTimer.Interval = this.interval; 
      int miniMapWidth = (int)(screenWidth * miniMapWidthPercentage); 
      int miniMapHeight = (int)(screenHeight * miniMapHeightPercentage); 
      int miniMapStartWidth = (screenWidth - miniMapWidth); 
      int miniMapStartHeight = (screenHeight - miniMapHeight); 

      bounds = new Rectangle(miniMapStartWidth, miniMapStartHeight, miniMapWidth, miniMapHeight); 
      bitmap = new Bitmap(bounds.Width, bounds.Height); 
      onSaveImage += imageHolder.RefreshImage; 
     } 

     public void Start() 
     { 
      aTimer.Enabled = true; 
     } 

     public void OnTimedEvent(object sender, ElapsedEventArgs e) 
     { 
      try 
      { 
       if (Busy) 
        return; 
       Busy = true; 
       using (Graphics g = Graphics.FromImage(bitmap)) 
       { 
        g.CopyFromScreen(new Point(bounds.Left, bounds.Top), Point.Empty, bounds.Size); 
        onSaveImage((byte[])converter.ConvertTo(bitmap, typeof(byte[]))); 
       } 
       Busy = false; 
      } 
      catch (Exception exception) 
      { 
       Console.WriteLine(exception.Message); 
      } 
     } 
    } 
} 

Voll Quellcode kann hier gefunden werden:

https://github.com/oldtimerza/Dota2Trainer

Wie es funktioniert, ist erstellt einfach einen Timer, dass nach einer gewissen Zeit die OnTimedEvent() -Methode der Screencapturer Klasse ausgeführt wird, die hat einen Delegaten, der die MiniMapOverlay RefreshImage() -Methode ausführt. Der Code ist im Moment schockierend, aber ich wollte nur eine grobe und fertige Version bekommen, bevor ich sie umgestalte.

Ich habe seit Jahren gesucht, warum dies passiert, irgendwelche Vorschläge?

+0

Ich glaube nicht, dass jemand Ihr gesamtes Projekt analysieren möchte, bitte posten Sie die relevanten Teile Ihres Quellcodes in Bezug auf das Problem. – mxmissile

+0

Projekt besteht nur aus 3 kleinen Klassen, ich habe gerade ihren Quellcode hinzugefügt, um die Notwendigkeit, die Git-Seite zu besuchen, zu entfernen. –

Antwort

1

Sie sollten Glib.Timeout statt System.Timers verwenden. Es kann zu Threading-Problemen mit System.Timers kommen und das Timer-Ereignis tritt auf einem anderen Thread als die GTK-Anwendung auf. Glib.Timeout reiht ein Ereignis in der Haupt-GTK-Anwendungsschleife in einem bestimmten Intervall ein und wird im selben Thread ausgeführt. Es eignet sich jedoch nicht für zeitkritische Funktionen, da die Anwendungsschleife andere Ereignisse wie Mausklicks behandelt. Ich habe Verzögerungen von etwa einer halben Sekunde bis zu einer Sekunde gesehen, aber das war beim Debuggen auf einem älteren Computer. Dies scheint kein Problem für Ihre Anwendung zu sein; nur für zukünftige Referenz. Glib.Timeout ruft weiterhin das Update-Ereignis auf, bis Sie false zurückgeben.

uint timerId; 

public void Start(uint interval) 
{ 
    timerId = GLib.Timeout.Add (interval, OnUpdateTimer); 
} 

protected bool OnUpdateTimer() 
{ 
    try 
    { 
     if (Busy) 
      return; 
     Busy = true; 
     using (Graphics g = Graphics.FromImage(bitmap)) 
     { 
      g.CopyFromScreen(new Point(bounds.Left, bounds.Top), Point.Empty, bounds.Size); 
      onSaveImage((byte[])converter.ConvertTo(bitmap, typeof(byte[]))); 
     } 
     Busy = false; 
    } 
    catch (Exception exception) 
    { 
     Console.WriteLine(exception.Message); 
    } 
    return true; 
} 
+0

Ich dachte, es könnte etwas mit Threading zu tun haben. Vielen Dank. Nur eine kleine Randnotiz, dass die "wenn (beschäftigt) zurückkehren;" Abschnitt muss einen Bool zurückgeben. –

Verwandte Themen