2016-07-21 23 views
0

C#、.Net 4.5、Gtk#を使って簡単なアプリケーションを作成しています。窓で数秒後に画像が消え、次のエラーが表示されます。Gtk#ウィンドウで画像を更新すると、一定時間が経過すると画像が消えます。

Glib-CRITICAL **:削除しようとしたときに、ソースID xxxxが見つかりませんでした。

関連コード:

の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); 
      } 
     } 
    } 
} 

完全なソースコードはここで見つけることができます:どのように動作

https://github.com/oldtimerza/Dota2Trainer

は、単純に、一定の時間が経過するScreencapturerクラスのOnTimedEvent()メソッドを実行することを、タイマーを作成しますさMiniMapOverlayのRefreshImage()メソッドを実行するデリゲートがあります。コードは現時点では衝撃的ですが、私はそれをリファクタリングする前に大まかで準備が整ったバージョンを稼働させたいと思っていました。

私はこれがなぜ起こったのか、何か提案してきた年齢層を探してきましたか?

+0

私はあなたのプロジェクト全体を解析したいとは思わないが、問題に関連するソースコードの関連部分を投稿してください。 – mxmissile

+0

プロジェクトは小規模な3つのクラスで構成されていますが、私はgitページにアクセスする必要性を排除するためにソースコードを追加しました。 –

答えて

1

System.Timersの代わりにGlib.Timeoutを使用してください。 System.Timersのスレッディング問題があり、タイマーイベントがGTKアプリケーションとは異なるスレッドで発生します。 Glib.Timeoutは一定の間隔でメインのGTKアプリケーションループにイベントをキューイングし、同じスレッドで実行します。しかし、アプリケーションループがマウスクリックなどの他のイベントを処理しているため、時間に敏感な関数には適していません。私は約0.5秒の遅延を見たことがありますが、それはデバッグ中の古いコンピュータ上でした。あなたのアプリケーションではこれは問題ではないようです。ちょうど将来の参考のために。また、Glib.Timeoutは、falseを返すまでupdateイベントを呼び出し続けます。

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

スレッドと関係があると思っていました。ありがとう。ちょっとしたことに、 "if(Busy)return;"セクションはboolを返す必要があります。 –

関連する問題