【问题标题】:WinForms Bitmap region is already lockedWinForms 位图区域已被锁定
【发布时间】:2016-01-25 02:12:38
【问题描述】:

我试图滑过几张图片,基本上你有 2 个向前和向后的按钮。它们的功能是滚动列表图像。一旦其中一个到达末尾,它必须返回到列表的另一侧。这就是我所拥有的

private List<Bitmap> RotatePacks = new List<Bitmap> { new Bitmap(@"Assets\All_Cards\All_Royal\All_Royal.png"),
                                                        new Bitmap(@"Assets\All_Cards\All_Classic\All_Classic.jpg")};

private void bNext_Click(object sender, EventArgs e)
{
    Bitmap currentImage = (Bitmap)pickCards.Image;
    for (int i = 0; i < RotatePacks.Count; i++)
    {
        if (AreEqual(currentImage, RotatePacks[i]))
        {
            try
            {
                pickCards.Image = RotatePacks[i + 1];
            }
            catch (Exception)
            {
                bPrevious_Click(sender, e);
                pickCards.Image = RotatePacks[i - 1];
            }
        }
    }
}
private void bPrevious_Click(object sender, EventArgs e)
{
    Bitmap currentImage = (Bitmap)pickCards.Image;
    for (int i = 0; i < RotatePacks.Count; i++)
    {
        if (AreEqual(currentImage, RotatePacks[i]))
        {
            try
            {
                pickCards.Image = RotatePacks[i - 1];
            }
            catch (Exception)
            {
                bNext_Click(sender, e);
            }
        }
    }
}

这是两个按钮。在这里,我试图将保存图像的图片框的图像与列表RotatePacks 进行比较。像这样我得到正在显示的当前图像。这是 AreEqual 方法:

public unsafe static bool AreEqual(Bitmap b1, Bitmap b2) // copy pasted
{
    if (b1.Size != b2.Size)
    {
        return false;
    }

    if (b1.PixelFormat != b2.PixelFormat)
    {
        return false;
    }

    /*if (b1.PixelFormat != PixelFormat.Format32bppArgb)
    {
        return false;
    }*/
    Rectangle rect = new Rectangle(0, 0, b1.Width, b1.Height);
    BitmapData data1
        = b1.LockBits(rect, ImageLockMode.ReadOnly, b1.PixelFormat);
    BitmapData data2
        = b2.LockBits(rect, ImageLockMode.ReadOnly, b1.PixelFormat);
    int* p1 = (int*)data1.Scan0;
    int* p2 = (int*)data2.Scan0;
    int byteCount = b1.Height * data1.Stride / 4; //only Format32bppArgb 

    bool result = true;
    for (int i = 0; i < byteCount; ++i)
    {
        if (*p1++ != *p2++)
        {
            result = false;
            break;
        }
    }

    b1.UnlockBits(data1);
    b2.UnlockBits(data2);

    return result;
}

所以现在回到我的问题,按钮按我想要的方式工作,但它们只工作一次。如果我按下下一个按钮而不是上一个按钮,或者我按下下一个按钮两次,程序将崩溃。它给了我一个例外

            BitmapData data2
            = b2.LockBits(rect, ImageLockMode.ReadOnly, b1.PixelFormat);

以下是实际异常的一些截图:

http://prntscr.com/9ug3nl

http://prntscr.com/9ug3vv

  • P.S 我正在使用这种比较方法,但我还没有编程。我从另一个 StackOverflow 问题中复制了代码

【问题讨论】:

  • 这只是一个疯狂的猜测......但你不认为值得早点检查if (b1 == b2) return true;吗?可能b1 == b2 会导致这个问题......

标签: c# winforms exception bitmap byte


【解决方案1】:

这里似乎有几个问题:

  1. 值得早点检查

    if (b1 == b2) //put this
        return true; 
    //do something else
    Rectangle rect = new Rectangle(0, 0, b1.Width, b1.Height);
    //and so on
    

    b1 == b2 可能会导致该问题

  2. 似乎您的LockBits 指的是相同的确切项目(相同的rect,相同的大小,某种模式,相同的像素格式):

    Rectangle rect = new Rectangle(0, 0, b1.Width, b1.Height);
    BitmapData data1
        = b1.LockBits(rect, ImageLockMode.ReadOnly, b1.PixelFormat);
    BitmapData data2
        = b2.LockBits(rect, ImageLockMode.ReadOnly, b1.PixelFormat);
    

    这可能是问题的另一个原因...

【讨论】:

  • 早期检查完成了工作,感谢一千次! :)
  • @Assim 所以,这一直是罪魁祸首...... ;) 很高兴知道这一点
【解决方案2】:

就像 Ian 指出的那样,您必须检查您尝试在 AreEqual() 方法中比较的图像(current imageRotatepacks[i] 中的图像)是否相同并且属于同一个实例?如果它们属于同一个实例,它显然会生成该异常。使用.Equals()方法检查图片是否属于同一个实例。

考虑一个图像实例

Bitmap img;

img 中的图像与RotatePacks 一样被加载到图片框中。在您的代码中,您试图两次锁定同一个实例,因此它会生成异常 Ian 指出的位图线没问题,但 2 个不同的图像可以具有相同的大小和像素格式。

如果真的是这样的话,我认为你不需要逐个像素地比较。我想你在Rotatepacks 中有Bitmap 实例。只需使用.Equals() 将图片框中的图像实例与Rotatepacks 中的图像实例进行比较

【讨论】:

    猜你喜欢
    • 2023-03-22
    • 1970-01-01
    • 2012-12-15
    • 1970-01-01
    • 1970-01-01
    • 2012-12-13
    • 2011-03-10
    • 1970-01-01
    • 2021-06-06
    相关资源
    最近更新 更多