简体   繁体   English

C#Pen抛出OutOfMemoryException

[英]c# Pen throws OutOfMemoryException

A form with a panel and boxes drawn on, the user clicks a box and a label appears for a moment to say "box hit". 一个带有面板和绘制框的表单,用户单击一个框,然后出现一个标签,说“框命中”。

I have a working version of the code but I tried to rearrange it to experiment with making it more efficient, and I find I am currently getting this exception. 我有一个有效的代码版本,但是我尝试对其进行重新排列以尝试使其更高效,并且我发现当前正在遇到此异常。

I do not understand why this exception is occurring, and I would like to be able to troubleshoot it but I don't know how to do that either. 我不明白为什么会发生此异常,我希望能够对其进行故障排除,但是我也不知道该怎么做。 I have narrowed it down to what line it is. 我将其范围缩小到了哪一行。 But beyond that I don't know. 但是除此之外,我不知道。

The error occurs when a box is clicked.. So the panel's mousedown is executed. 单击框时会发生错误。.因此执行面板的mousedown。

All the controls eg panel, label, are programmatically generated, such that it should hopefully be possible for anybody to copy/paste the code change the classname and reproduce the exception that I get. 所有控件(例如面板,标签)都是以编程方式生成的,因此希望任何人都可以复制/粘贴代码以更改类名并重现我得到的异常。

I have read online that the pen might generate an outofmemoryexception even when it's not really out of memory, but it's just throwing that exception, though that still doesn't tell me why or how it can be avoided, so that I can understand how to write code where the pen doesn't throw that exception. 我已经在线阅读了有关笔的信息,即使它不是真的没用完,它也可能会产生内存不足的异常,但这只是抛出该异常,尽管那仍然没有告诉我为什么或如何避免这种异常,以便我可以理解如何在笔不会抛出该异常的地方编写代码。

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Drawing.Drawing2D;

namespace WindowsFormsApplication17
{
    public partial class Form1 : Form
    {
        Label lbl1;
        Panel panel;
        Timer timer1;

        Point[][] points = new Point[9][];

        GraphicsPath[] gps = new GraphicsPath[9];

        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            panel = new Panel();


            lbl1 = new Label();
            timer1 = new Timer();

            this.Controls.Add(panel);

            Label alias = lbl1;
            alias.Text = "box clicked";
            alias.Visible = false;

            panel.BackgroundImageLayout = ImageLayout.Stretch;
            this.Height = 500; this.Width = 500;


            panel.Controls.Add(lbl1);

            panel.MouseDown += p_MouseDown;
            timer1.Tick += timer1_Tick;

            panel.BackColor = Color.White;
            panel.Height = 400;
            panel.Width = 400;


            for (int i = 0; i < 9; i++) points[i] = new Point[4];

            points[0][0] = new Point(19, 262);
            points[0][1] = new Point(28, 257);
            points[0][2] = new Point(27, 284);
            points[0][3] = new Point(16, 285);


            points[1][0] = new Point(52, 253);
            points[1][1] = new Point(62, 250);
            points[1][2] = new Point(61, 277);
            points[1][3] = new Point(49, 278);


            points[2][0] = new Point(87, 249);
            points[2][1] = new Point(100, 248);
            points[2][2] = new Point(99, 275);
            points[2][3] = new Point(86, 274);

            points[3][0] = new Point(126, 250);
            points[3][1] = new Point(140, 252);
            points[3][2] = new Point(139, 279);
            points[3][3] = new Point(126, 277);


            points[4][0] = new Point(164, 257);
            points[4][1] = new Point(175, 260);
            points[4][2] = new Point(175, 287);
            points[4][3] = new Point(164, 284);

            points[5][0] = new Point(197, 265);
            points[5][1] = new Point(209, 269);
            points[5][2] = new Point(209, 295);
            points[5][3] = new Point(198, 292);


            points[6][0] = new Point(228, 273);
            points[6][1] = new Point(241, 275);
            points[6][2] = new Point(240, 300);
            points[6][3] = new Point(229, 300);

            points[7][0] = new Point(262, 274);
            points[7][1] = new Point(274, 273);
            points[7][2] = new Point(275, 300);
            points[7][3] = new Point(262, 301);

            points[8][0] = new Point(297, 272);
            points[8][1] = new Point(308, 268);
            points[8][2] = new Point(311, 295);
            points[8][3] = new Point(298, 296);


            panel.Paint += thepanel_Paint;


            // I can see that I can remove all the braces, but anyhow.
            for (int i = 0; i < 9; i++)
            {
                using (gps[i] = new GraphicsPath())
                using (Pen pen = new Pen(Color.Black, 1))  //this pen is not for drawing. but for the logic re graphicspath
                {
                    gps[i].AddPolygon(points[i]);                  
                }
            }


        }




        void p_MouseDown(object sender, EventArgs e)
        {

            MouseEventArgs mea = (MouseEventArgs)e;

            //GraphicsPath[] gps = new GraphicsPath[9];
            bool boxhit = false;


            for (int i = 0; i < 9; i++)
            {
                using (Pen pen = new Pen(Color.Black, 1))  //this pen is not for drawing. but for the logic re graphicspath
                {

                    bool cond1=false; 
                    bool cond2=false;  


                    cond1 = gps[i].IsOutlineVisible(new Point(mea.X, mea.Y), pen);
                    cond2 = gps[i].IsVisible(new Point(mea.X, mea.Y));



                    if (cond1 == true ||
                        cond2 == true)
                    {
                        boxhit = true;
                        lbl1.Visible = true;
                        timer1.Enabled = true;
                    }


                }


            } //for

            // if (boxhit == false) MessageBox.Show("no box hit");


        }


        private void timer1_Tick(object sender, EventArgs e)
        {
            lbl1.Visible = false; timer1.Enabled = false;

        }



        private void thepanel_Paint(object sender, PaintEventArgs e)
        {
            GraphicsPath[] gps = new GraphicsPath[9];

            Graphics gg = panel.CreateGraphics();

            for (int i = 0; i < 9; i++)
                using (gps[i] = new GraphicsPath())
                {
                    gps[i].AddPolygon(points[i]);
                    gg.DrawPath(new Pen(Color.Blue, 1), gps[i]);
                }

        }
    }
}

As a side note, here is the code prior to rearrangement, where it works, it doesn't throw an exception (though it's perhaps inefficient in that every mousedown it adds polygons to determine which is clicked, when really that only needs to be done once). 附带说明一下,这是重新排列之前的代码,可以正常工作,但不会引发异常(尽管效率低下,因为每次鼠标按下时它都会添加多边形来确定单击的对象,而实际上只需要这样做即可)一旦)。

在此处输入图片说明

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Drawing.Drawing2D;

namespace WindowsFormsApplication15
{
    public partial class Form1 : Form
    {
        Label lbl1;
        Panel panel;
        Timer timer1;

        Point[][] points = new Point[9][];


        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            panel = new Panel();


            lbl1 = new Label();
            timer1 = new Timer();

            this.Controls.Add(panel);

            Label alias = lbl1;
            alias.Text = "box clicked";
            alias.Visible = false;

            panel.BackgroundImageLayout = ImageLayout.Stretch;

            this.Height = 500; this.Width = 500;


            panel.Controls.Add(lbl1);

            panel.MouseDown += p_MouseDown;
            timer1.Tick += timer1_Tick;

            panel.BackColor = Color.White;
            panel.Height = 400;
            panel.Width = 400;

            for (int i = 0; i < 9; i++) points[i] = new Point[4];

            points[0][0] = new Point(19, 262);  //left top
            points[0][1] = new Point(28, 257); //right top
            points[0][2] = new Point(27, 284);   //right bottom
            points[0][3] = new Point(16, 285);  //left bottom


            points[1][0] = new Point(52, 253);
            points[1][1] = new Point(62, 250);
            points[1][3] = new Point(49, 278);
            points[1][2] = new Point(61, 277);

            points[2][0] = new Point(87, 249);
            points[2][1] = new Point(100, 248);
            points[2][3] = new Point(86, 274);
            points[2][2] = new Point(99, 275);

            points[3][0] = new Point(126, 250);
            points[3][1] = new Point(140, 252);
            points[3][3] = new Point(126, 277);
            points[3][2] = new Point(139, 279);

            points[4][0] = new Point(164, 257);
            points[4][1] = new Point(175, 260);
            points[4][3] = new Point(164, 284);
            points[4][2] = new Point(175, 287);

            points[5][0] = new Point(197, 265);
            points[5][1] = new Point(209, 269);
            points[5][3] = new Point(198, 292);
            points[5][2] = new Point(209, 295);

            points[6][0] = new Point(228, 273);
            points[6][1] = new Point(241, 275);
            points[6][3] = new Point(229, 300);
            points[6][2] = new Point(240, 300);

            points[7][0] = new Point(262, 274);
            points[7][1] = new Point(274, 273);
            points[7][3] = new Point(262, 301);
            points[7][2] = new Point(275, 300);

            points[8][0] = new Point(297, 272);
            points[8][1] = new Point(308, 268);
            points[8][3] = new Point(298, 296);
            points[8][2] = new Point(311, 295);


            panel.Paint += thepanel_Paint;

        }


        void p_MouseDown(object sender, EventArgs e)
        {
            MouseEventArgs mea = (MouseEventArgs)e;

            GraphicsPath[] gps = new GraphicsPath[9];
            bool boxhit = false;


            for (int i = 0; i < 9; i++)
            {
                using (gps[i] = new GraphicsPath())
                using (Pen pen = new Pen(Color.Black,1))  //this pen is not for drawing. but for the logic re graphicspath
                {

                    gps[i].AddPolygon(points[i]);


                    if (gps[i].IsOutlineVisible(new Point(mea.X, mea.Y), pen) == true || gps[i].IsVisible(new Point(mea.X, mea.Y))) 
                    {
                        boxhit = true;
                        lbl1.Visible = true;
                        timer1.Enabled = true;
                    }


                }

            } //for

           // if (boxhit == false) MessageBox.Show("no box hit");


        }


        private void Form1_MouseDown(object sender, MouseEventArgs e)
        {



        }

        private void Form1_Paint(object sender, PaintEventArgs e)
        {

        }

        private void timer1_Tick(object sender, EventArgs e)
        {
            lbl1.Visible = false; timer1.Enabled = false;

        }



        private void thepanel_Paint(object sender, PaintEventArgs e)
        {
            GraphicsPath[] gps = new GraphicsPath[9];

            Graphics gg = panel.CreateGraphics();

            for (int i = 0; i < 9; i++)
                using (gps[i] = new GraphicsPath())
                {
                    gps[i].AddPolygon(points[i]);
                    gg.DrawPath(new Pen(Color.Blue, 1), gps[i]);
                }

        }
    }
}

Added 添加

In reply to Hans's comment. 回应汉斯的评论。

I see I missed a using there for that graphics object in the panel paint procedure. 我知道我错过了一个using那里的面板漆过程中该图形对象。 But if I add it, so, with this code. 但是,如果我添加它,则使用此代码。

 using(Graphics gg = panel.CreateGraphics())
            for (int i = 0; i < 9; i++)
                using (gps[i] = new GraphicsPath())
                {
                    gps[i].AddPolygon(points[i]);
                    gg.DrawPath(new Pen(Color.Black, 1), gps[i]);
                }

I still get the same exception on the cond1 = gps[i].IsOutlineVisible(new Point(mea.X, mea.Y), pen); 我仍然在cond1 = gps[i].IsOutlineVisible(new Point(mea.X, mea.Y), pen);cond1 = gps[i].IsOutlineVisible(new Point(mea.X, mea.Y), pen);相同的异常cond1 = gps[i].IsOutlineVisible(new Point(mea.X, mea.Y), pen); line in the p_MouseDown procedure. p_MouseDown过程中的p_MouseDown

Added further 进一步增加

the Q is answered, but a further weird thing.. I tried to create a simple program that gives the same exception, but the program didn't crash or run correctly so maybe whether a runtime error occurs or not isn't that clearly predicatable. 问了答案,但还有一个更奇怪的事情。我试图创建一个提供相同异常的简单程序,但是该程序没有崩溃或无法正确运行,因此也许是否发生运行时错误不是很明显。 Here i'd expect an outofmemoryexception, or at least two messageboxes not just one, and I get no exception and just one messagebox. 在这里,我期望内存不足的异常,或者至少有两个消息框,而不仅仅是一个,我也没有例外,只有一个消息框。

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace blah
{
    public partial class Form1 : Form
    {
        Pen p;

        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            MessageBox.Show("sadf"); //displays
            MessageBox.Show(p.Color.ToString()); // doesn't display a messagebox at all!
        }

    }
}

Besides you are initializing a Pen and some other objects you are not using, you use using keyword to create your GraphicsPath s. 除了要初始化Pen和不使用的其他对象外,还可以使用using关键字创建GraphicsPath So what happens when you exit the using statement... yes, object is disposed. 那么,当您退出using语句时会发生什么……是的,对象已被处置。

Instead, try creating your paths eg 相反,尝试创建路径,例如

for (int i = 0; i < 9; i++)
{
    gps[i] = new GraphicsPath();
    gps[i].AddPolygon(points[i]);
}

So this really has nothing to do with app getting OutOfMemory ... but yeah, exception is misleading at least. 因此,这与应用程序获取OutOfMemory无关。但是,是的,异常至少会引起误解。

Using above your app works but as @Hans Passant stated, you are still leaking memory. 在您的应用上使用可以正常工作,但正如@Hans Passant所说,您仍然在泄漏内存。

Edit: 编辑:

Here's a re-write of your code, just "because" :). 这是您的代码的重新编写,只是“因为” :)。 Hope it helps and/or makes sense. 希望它能帮助和/或说得通。

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace WindowsFormsApplication1
{
    // It's preferred to use established naming conventions,
    // such as prefixing private fields with "_".

    // Declaring access modifiers explicitly, even default modifier
    // "private", is advised because it makes reading thousands lines of code
    // that much easier (one can expect first keyword to be access modifier)

    public partial class Form1 : Form
    {
        // For convenience and readability, 
        // I'd prefer Lists and List-of-Lists over arrays
        private readonly List<List<Point>> _points = new List<List<Point>>();
        private readonly List<GraphicsPath> _graphicsPaths = new List<GraphicsPath>();

        public Form1()
        {
            InitializeComponent();

            // Points to create paths from    
            _points.AddRange(new[] 
            {
                new List<Point>
                {
                    new Point(19, 62),
                    new Point(28, 57),
                    new Point(27, 84),
                    new Point(16, 85)
                },
                new List<Point>
                {
                    new Point(52, 53),
                    new Point(62, 50),
                    new Point(61, 77),
                    new Point(49, 78)
                },
                new List<Point>
                {
                    new Point(87, 49),
                    new Point(100, 48),
                    new Point(99, 75),
                    new Point(86, 74)
                }
            });

            // Create GDI graphics paths    
            foreach (List<Point> points in _points)
            {
                GraphicsPath path = new GraphicsPath();
                path.AddPolygon(points.ToArray());
                _graphicsPaths.Add(path);
            }
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            // Adjust form
            Height = 200;
            Width = 100;

            // Create label and panel
            // No need for these to be private fields
            Label label = new Label
            {
                Text = @"Border clicked",
                Visible = false
            };

            // Create panel
            Panel panel = new Panel
            {
                Height = 400,
                Width = 400,
                BackColor = Color.White,
                BackgroundImageLayout = ImageLayout.Stretch
            };

            // Paint event handler.
            // Personally I prefer inline anonymous methods
            // over named methods when logic is simple 
            // and it's not being reused    
            panel.Paint += (o, args) =>
            {
                // 'using' because we want to get rid of Graphics
                // and Pen when we are done drawing paths
                using (Graphics graphics = panel.CreateGraphics())
                {
                    using (Pen pen = new Pen(Color.Blue, 3))
                    {
                        foreach (GraphicsPath path in _graphicsPaths)
                            graphics.DrawPath(pen, path);
                    }
                }
            };

            // Mouse (down) event handler.     
            panel.MouseDown += (o, args) =>
            {
                // Get mouse point
                Point mousePoint = new Point(args.X, args.Y);

                // Again, we want to dispose Pen
                using (Pen pen = new Pen(Color.Transparent, 0F))
                {
                    // Get first path under mouse pointer  
                    GraphicsPath path = _graphicsPaths.FirstOrDefault(p =>
                        p.IsOutlineVisible(mousePoint, pen));

                    if (path == null)
                        return;

                    // If found, "flash" our informative label
                    // in non-blocking way  
                    Task.Run(() =>
                    {
                        label.Invoke((Action)(() => label.Visible = true));
                        Thread.Sleep(500);
                        label.Invoke((Action)(() => label.Visible = false));
                    });
                }
            };

            // Add controls to containers 
            panel.Controls.Add(label);                
            Controls.Add(panel);
        }

        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            // This could be more reasonable place to dispose
            // GDI Graphics path created earlier? 
            foreach (GraphicsPath path in _graphicsPaths)
                path.Dispose();
            _graphicsPaths.Clear();
        }
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM