-1

我的问题是:

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 个对象时

显示此错误。

4

3 回答 3

2

我的问题是:

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

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

并且处理它们并没有真正帮助,因为您不能再使用已处理的对象..

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

最常见的方法是:保留图像列表(当它们 <= 256x256 像素时,将它们放入ImageList!)并在板的Paint事件中绘制它们。这将消除与PictureBoxes.

(旁白:人们可能认为这不会对所有DrawImage调用都有效。但所有这些PictureBoxes还需要在所有表面上绘制所有像素,所以这没有问题。但它们也必须承担存在的开销(在hood) 功能齐全windows(请参阅错误消息!),这就是为什么系统只能拥有有限数量的控件;始终尝试保持控件的数量< 1k!)

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

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

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

  • 不会有您可以使用的Enter或事件。Leave相反,您需要通过在 MouseMove 事件中对其进行测试来检测进入一块区域。如果你保留一个List<Rectangle>你可以Rectangle.Contains(e.Location)用于这个测试。

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

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

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

Paint另一种选择是在事件中使用您现在用来创建它们的相同计算直接从原始图像中提取像素数据。(有一个DrawImage覆盖使用两个Rectangles,一个用于确定目标,一个用于源区域。)这可以节省GDI句柄,至少如果您不能使用ImageList.

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

祝你好运 :-)

于 2018-09-05T09:32:19.653 回答
1

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

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

于 2018-09-17T12:12:32.437 回答
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);
        }
于 2018-09-04T07:54:02.427 回答