【问题标题】:Graphics.ReleaseHdc() throws ArgumentException error with multi-threaded instancesGraphics.ReleaseHdc() 使用多线程实例引发 ArgumentException 错误
【发布时间】:2014-09-09 07:59:09
【问题描述】:

我有一个游戏,有几个敌人,每个都在自己的线程中运行以进行移动和绘图。敌人被绘制在面板上,因此他们的线程必须访问面板的图形。我已经使用Lock 保护了CreateGraphics 调用,当我想ReleaseHdc 面板的图形时,我得到一个System.ArgumentException,即使我调用ReleaseHdc 方法时没有任何参数. 以下是相关代码(p 是作为静态变量传递下来的 Panel 引用并指向正确的控件):

//Member region
internal Bitmap Img = new Bitmap(Image.FromFile(@"Enemy.png"), Size);
internal static readonly object _Lock = new object();

//from enemy's custom Move() method
lock (_Lock)
{
    Graphics gfx = p.CreateGraphics();
    gfx.DrawImage(Img, Location);
    gfx.ReleaseHdc(); // gfx.Dispose() works here                     
}

考虑到我需要在自己的线程中将每个元素绘制到同一个面板上的多线程访问,是否有人知道我为什么会收到此错误和/或如何修复它?

[编辑]

使用gfx.Dispose() 而不是ReleaseHdc() 就可以了。 虽然结果并不令人满意,因为我得到了一个非常不稳定的图像,敌人闪烁。这可能是经常重复绘制它们的问题,并且与我的问题无关 - 或者这个问题与我如何处理多个线程之间存在联系?

【问题讨论】:

  • 你在玩一个非常危险的游戏。那个锁当然是个好主意,但是你没有把同样的锁放在面板的 OnPaint() 方法中。从 Panel 派生您自己的类并覆盖 OnPaint() 和 OnPaintBackground()。使用 ReleaseHdc() 是错误的,您必须改用 Dispose()。可能会奏效,但不要抱太大希望。
  • 在创建多个控件的Graphpics 实例时是否存在冲突?是否可以同时存在一个线程,从而不可能每个线程都创建自己的线程?我现在正在修改我的程序以从Panel 派生,但无论如何我都会很高兴。
  • 在多个线程中创建图形实例很好。使用 DpiX 之类的属性很好。像 MeasureString() 这样的东西很好。实际上使用它们在屏幕上绘画,这是一个危险的游戏。当多个线程渲染到同一个屏幕区域时,也很难推断你最终会得到什么,最终结果总是不可预测的。
  • 您知道这是如何正确完成的吗?我可以重写我的程序,但现在我不知道如何从多个线程将DrawImage 转换为Panel。或者是使用来自线程的更新参数(如位置)从后台线程绘制面板上的所有内容的秘诀,也许?
  • 游戏代码中的样板是渲染到后台缓冲区并将其blit到屏幕上。通过绘制位图很简单,可以由工作线程安全地完成。

标签: c# image graphics argumentexception


【解决方案1】:

如果你要打电话给gfx.ReleaseHdc(),你不应该打电话给gfx.GetHdc()吗?

我认为你的代码应该是这样的:

lock (_Lock)
{
    using (var gfx = p.CreateGraphics())
    {
        gfx.DrawImage(Img, Location);
    }
}

我还发现对CreateGraphics() 的调用本身有点可疑。我希望将Graphics 对象提供给 绘图代码,而不是 它创建。

【讨论】:

  • 这仍然会引发相同的异常。但请参阅我上面的编辑 - 使用 Dispose() 有效。
  • @Johannes 但是我在上面发布的代码是使用 Dispose()!这就是using 所做的......如果它抛出相同的异常,则意味着问题不在于ReleaseHdc(),因为我发布的代码甚至没有调用它......
  • 哦,抱歉,我没有意识到,也没有删除ReleaseHdc()!与手动输入 Dispose 完全一样,谢谢!关于您的其他评论:有没有一种为每个线程提供 Panel.CreateGraphics 的好方法?我想通过静态变量设置它并用 Lock 保护它应该可以吗?之前很简单的尝试过,报错,所以尝试用这种方式创建。
  • 我按照您的建议将 CreateGraphics 重新设置为主要表单的静态引用,并且它有效。遗憾的是,闪烁问题没有任何改善,但更好的代码可读性。 ;)
  • @Johannes 对于多线程我猜你需要像这样动态地创建图形对象,因为你不允许在线程之间共享它。但是,如果线程在循环中运行,您应该能够在线程开始时创建一次图形对象(但请记住在线程退出时释放它)。
猜你喜欢
  • 1970-01-01
  • 2018-04-23
  • 1970-01-01
  • 2017-04-23
  • 1970-01-01
  • 2018-06-08
  • 1970-01-01
  • 2013-06-02
  • 1970-01-01
相关资源
最近更新 更多