System.ComponentModel.Win32Exception: 'Error creating window handle.'



我的问题是:

System.ComponentModel.Win32Exception:"创建窗口句柄时出错"。

我知道我可以用Dispose()解决这个问题,但是当我在程序中使用它时,我显示另一个错误:

System.ObjectDisposedException:"无法访问已释放的对象。 对象名称:"图片框"。'

我使用以下代码:

private void SetUpPuzzle_Click(int parts)
{
Panel P = new Panel
{
Size = new Size(200, 200),
Location = new Point(394, 62),
};
Controls.Add(P);
Control board = P;
int total = parts * parts;
var PB = new PictureBox[total];
var imgarray = new Image[total];
var img = User_Image.Image;
int W = img.Width / (int.Parse(Math.Sqrt(double.Parse(parts.ToString())).ToString()));
int H = img.Height / (int.Parse(Math.Sqrt(double.Parse(parts.ToString())).ToString()));
int size = 200 / (int.Parse(Math.Sqrt(double.Parse(parts.ToString())).ToString()));
for (int x = 0; x < parts; x++)
{
for (int y = 0; y < parts; y++)
{
var index = x * parts + y;
imgarray[index] = new Bitmap(W, H);
using (Graphics graphics = Graphics.FromImage(imgarray[index]))
graphics.DrawImage(img, new Rectangle(0, 0, W, H),
new Rectangle(x * W, y * H, W, H), GraphicsUnit.Pixel);
PB[index] = new PictureBox
{
Name = "P" + index,
Size = new Size(size, size),
Location = new Point(x * size, y * size),
Image = imgarray[index],
SizeMode = PictureBoxSizeMode.StretchImage
};
PB[index].MouseEnter += Images_M_E;
PB[index].MouseLeave += Images_M_L;
PB[index].MouseClick += Form_MouseClick;
*PB[index].Dispose();
*board.Controls.Add(PB[index]);
}
}
}

当我想创建 10,000 个对象时

将显示此错误。

我的问题是:

System.ComponentModel.Win32Exception:"创建窗口句柄时出错"。

事实上。您正在为Winforms应用程序创建太多控件

处理它们并没有真正的帮助,因为你不能再使用处置的对象了。

要拥有这种大拼图(10k块(,您需要从使用PictureBoxes(或任何其他Controls(来显示拼图更改为不同的方法。这在最初的问题中已经提出过,但后来你只想有100件,记得吗?

最常见的方法是:保留一个图像列表(当它们<= 256x256像素时,将它们放入ImageList!(并在棋盘的Paint事件中绘制它们。这将消除与PictureBoxes相关的所有开销。

(旁白:人们可能认为这不会在所有DrawImage调用中发挥作用。但是所有这些PictureBoxes还需要在其所有表面上绘制所有像素,因此这不是问题。但是它们还必须承担(引擎盖下(功能齐全windows的开销(请参阅错误消息!(,这就是为什么系统只能拥有有限数量的它们;始终尝试将控件数量保持在1K <</strong>!

您必须将放置逻辑移动到电路板的Paint事件,并且还必须更改事件模型..:

与其让每个PictureBox都响应自己的事件,不如找到一种方法来完成董事会事件中的所有工作。这必须是不同的,具体取决于事件。

由于我们不知道您有哪个事件,他们做了什么以及他们的工作需要哪些数据,因此很难提供所有必要的细节,所以我只指出几件事..:

  • 不会有您可以使用EnterLeave事件。相反,您需要通过在 MouseMove 事件中测试进入一块区域来检测进入该区域。如果您保留List<Rectangle>则可以使用此测试Rectangle.Contains(e.Location)

  • 您可以检测到鼠标单击,但随后必须找出单击的区域。如果 MouseMove 中的 Enter 和 Leave 逻辑正常工作,则可以使用其结果来了解单击的位置。

类似的想法可以用于所有其他事件;有些很简单,有些需要一点计算,但它们都很快,很容易实现。

要优化性能,请尝试使图像n大小合适,并使用Format32bppPArgb作为像素格式,因为它显示速度更快。

另一种选择是直接从Paint事件中的原始图像中提取像素数据,使用您现在用于创建它们的相同计算。(有一个DrawImage叠加层使用两个Rectangles,一个用于确定目标,一个用于源区域。这样可以节省GDI句柄,至少在无法使用ImageList的情况下。

始终为增长做好计划!为了更好的实现,请创建一个Piece类。它应该在ImageListImages集合中保存一个Rectangle和一个整数索引。它还可以有一个方法Switch(Piece otherPiece)可以切换Rectangles或索引。

祝你好运:-(

我遇到了这个异常,因为无限循环创建新的 UI 控件并设置其属性。循环多次后,当更改控件可见属性时,将抛出此 excp。我发现用户对象和GDI对象(从任务管理器(都很大。

我想您的问题与这些 UI 控件耗尽系统资源的原因类似。

PB[index].Dispose();评论,这是工作。

private void SetUpPuzzle(int parts)
{
// Comment ***********
//Panel P = new Panel
//{
//    Size = new Size(200, 200),
//    Location = new Point(394, 62),
//};
//Controls.Add(P);
//Control board = P;     ***********
int total = parts * parts;
var PB = new PictureBox[total];
var imgarray = new Image[total];
var img = User_Image.Image;
int W =Convert.ToInt32(img.Width / Math.Sqrt(parts));
int H = Convert.ToInt32(img.Height / Math.Sqrt(parts));
int size = Convert.ToInt32(200 / Math.Sqrt(parts));
for (int x = 0; x < parts; x++)
{
for (int y = 0; y < parts; y++)
{
var index = x * parts + y;
imgarray[index] = new Bitmap(W, H);
using (Graphics graphics = Graphics.FromImage(imgarray[index]))
graphics.DrawImage(img, new Rectangle(0, 0, W, H),
new Rectangle(x * W, y * H, W, H), GraphicsUnit.Pixel);
PB[index] = new PictureBox
{
Name = "P" + index,
Size = new Size(size, size),
Location = new Point(x * size, y * size),
Image = imgarray[index],
SizeMode = PictureBoxSizeMode.StretchImage
};
PB[index].MouseEnter += Form1_MouseEnter; 
PB[index].MouseLeave += Form1_MouseLeave; 
PB[index].MouseClick += Form1_MouseClick; 
//Comment                         
//PB[index].Dispose();       < -----------------
// Add PB in Panel in form
panel1.Controls.Add(PB[index]);

}
}
// after add all refresh panel
panel1.Refresh();
}

private void Form1_MouseClick(object sender, MouseEventArgs e)
{
throw new NotImplementedException();
}
private void Form1_MouseLeave(object sender, EventArgs e)
{
throw new NotImplementedException();
}
private void Form1_MouseEnter(object sender, EventArgs e)
{
throw new NotImplementedException();
}

然后在按钮中调用SetUpPuzzle方法,如下所示:

private void button1_Click(object sender, EventArgs e)
{
SetUpPuzzle(10);
}

相关内容

最新更新