我的问题是:
System.ComponentModel.Win32Exception:“创建窗口句柄时出错”。
我知道我可以用Dispose()
解决这个问题,但是当我在程序中使用它时,我正在显示另一个错误:
System.ObjectDisposedException:'无法访问已处置的对象。 对象名称:“ PictureBox”。 '
我使用以下代码:
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个对象时
显示此错误。
答案 0 :(得分:2)
我的问题是:
System.ComponentModel.Win32Exception:“创建窗口句柄时出错”。
的确。您正在为Winforms
应用创建过多的控件。
处置它们并没有真正的帮助,因为您不能再使用处置的对象。
要拥有这种大拼图( 10k 个),您需要从使用PictureBoxes
(或任何其他Controls
)显示为不同的拼图中改变方法。 original question中已经提出了这一建议,但是您只想拥有 100 个,记得吗?
最常见的方法是:保留一张图像列表(当它们为<= 256x256像素时,将其放入ImageList
!)并在板子的Paint
事件中绘制它们。这将消除PictureBoxes
所涉及的所有开销。
(此外:人们可能会认为这对所有DrawImage
调用都不起作用。但是所有PictureBoxes
都需要在其所有表面上绘制所有像素,所以这没有问题。但是它们还必须承担(在幕后)功能完整的windows
的开销(请参见错误消息!),这就是为什么系统只能包含数量有限的原因;请始终尝试保持数量不变的控件 <1k !)
您将不得不将放置逻辑移至董事会的Paint
事件,并且还必须更改事件模型。.
代替让每个PictureBox
响应自己的事件,您必须找到一种方法来完成董事会事件中的所有工作。这必须有所不同,具体取决于事件。
由于我们不知道您遇到了什么事件,他们做了什么以及他们的工作需要哪些数据,因此很难提供所有必要的详细信息,因此,我只指出一些事情..:< / p>
您将无法使用Enter
或Leave
事件。相反,您需要通过在MouseMove事件中进行测试来检测是否进入了某个区域。如果您保留List<Rectangle>
,则可以使用Rectangle.Contains(e.Location)
进行此测试。
您可以检测到MouseClick,但是随后必须找出被单击的区域。如果MouseMove的Enter和Leave逻辑正常运行,则可以使用其结果来了解Click的去向。
类似的想法可以用于所有其他事件;有些很简单,有些需要一些计算,但是它们都将很快并且很容易实现。.
要优化性能,请尝试使图像的大小合适,并使用Format32bppPArgb作为像素格式,因为显示速度更快。
另一种选择是使用现在用于创建像素的相同计算,从Paint
事件中的原始图像中直接提取像素数据。 (有一个DrawImage
叠加层,使用两个Rectangles
,一个用来确定目标,另一个用于源区域。)这样可以节省GDI
的句柄,至少在您不能使用时ImageList
。
始终计划增长!为了更好的实现,请创建一个Piece
类。它应包含Rectangle
的{{1}}集合中的ImageList
和一个整数索引。它还可以使用方法Images
来切换Switch(Piece otherPiece)
或索引。
祝你好运:-)
答案 1 :(得分:1)
我遇到了此异常,因为无休止的循环创建了新的UI控件并设置了其属性。经过多次循环后,更改控件的可见属性将引发此异常。我发现用户对象和GDI对象(来自任务管理器)都很大。
我猜您的问题与这些UI控件耗尽系统资源的原因类似。
答案 2 :(得分:0)
我评论了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);
}