Исключение GetRoundedRegion

1

Я создал пользовательскую кнопку с закругленными краями, я использую CreateRoundRectRgn для этого, в событии paint это вызвано для округления всех краев, когда я запускаю свою программу, все работает нормально, пока через минуту не появится следующее исключение (значение p = 0):

Изображение 174551

нужно добавить одно: кнопка подвергается примерно 50 событиям краски в секунду из-за затухания цвета (мигает)

это мое событие рисования:

 protected override void OnPaint(PaintEventArgs e)
    {
        this.SuspendLayout();

        this.Region = GetRoundedRegion(this.Width, this.Height);

        base.OnPaint(e);

        if (!this.Enabled)
            e.Graphics.Clear(this.DisabledColor);
        else if (Blinking)
            e.Graphics.Clear(Color.FromArgb(blinkingIntensity, this.BlinkColor));
        else if (this.Pressed)
            e.Graphics.Clear(this.PressedColor);
        else if (this.Selected)
            e.Graphics.Clear(this.SelectedColor);
        else
            e.Graphics.Clear(this.Color);


        using (Pen blackPen = new Pen(Color.FromArgb(150, Color.Black), 2))
        using (Pen whitePen = new Pen(Color.FromArgb(150, Color.Black), 2))
        {
            if (Pressed)
            {
                e.Graphics.DrawLines(blackPen, new[] { new Point(0, this.Height), new Point(0, 0), new Point(this.Width, 0) });
                e.Graphics.DrawArc(blackPen, new Rectangle(0, 0, _Radius, _Radius), 180, 90);

                e.Graphics.DrawLines(whitePen, new[] { new Point(0, this.Height - 2), new Point(this.Width - 2, this.Height - 2), new Point(this.Width - 2, 0) });
                e.Graphics.DrawArc(whitePen, new Rectangle(this.Width - 2 - _Radius, this.Height - 2 - _Radius, _Radius, _Radius), 0, 90);

                using (LinearGradientBrush lb = new LinearGradientBrush(new Point(0, 0), new Point(0, this.Height), Color.FromArgb(150, Color.Black), Color.FromArgb(100, Color.White)))
                {
                    e.Graphics.FillRectangle(lb, 0, 0, this.Width, this.Height);
                }
            }
            else
            {
                e.Graphics.DrawLines(whitePen, new[] { new Point(0, this.Height), new Point(0, 0), new Point(this.Width, 0) });
                e.Graphics.DrawArc(whitePen, new Rectangle(0, 0, _Radius, _Radius), 180, 90);

                e.Graphics.DrawLines(blackPen, new[] { new Point(0, this.Height - 2), new Point(this.Width - 2, this.Height - 2), new Point(this.Width - 2, 0) });
                e.Graphics.DrawArc(blackPen, new Rectangle(this.Width - 2 - _Radius, this.Height - 2 - _Radius, _Radius, _Radius), 0, 90);

                using (LinearGradientBrush lb = new LinearGradientBrush(new Point(0, 0), new Point(0, this.Height), Color.FromArgb(100, Color.White), Color.FromArgb(150, Color.Black)))
                {
                    e.Graphics.FillRectangle(lb, 0, 0, this.Width, this.Height);
                }
            }
        }

        int pressedoffset = 0;
        if (Pressed)
            pressedoffset = 2;

        int maxWidth = this.Width - 20;

        // Set up string.
        string measureString = Text;

        Font stringFont = Font;

        // Set maximum width of string.
        int stringWidth = this.Width - 20;

        SizeF stringSize = new SizeF();

        // Set string format.
        using (StringFormat newStringFormat = new StringFormat())
        {
            newStringFormat.FormatFlags = StringFormatFlags.DisplayFormatControl;

            stringSize = e.Graphics.MeasureString(measureString, stringFont, stringWidth, newStringFormat);
        }
        // Draw string to screen.
        if (CenterText)
            e.Graphics.DrawString(measureString, stringFont, Brushes.White, new PointF(((this.Width / 2) - (stringSize.Width / 2)) + pressedoffset, ((this.Height / 2) - (stringSize.Height / 2)) + pressedoffset));
        else
            e.Graphics.DrawString(measureString, stringFont, Brushes.White, new PointF(10 + pressedoffset, ((this.Height / 2) - (stringSize.Height / 2)) + pressedoffset));

        this.ResumeLayout();
    }
  • 0
    Похоже, проблема не в коде C #, а в вызове библиотеки CreateRoundRectRgn CreateRoundRectRgn, который по какой-то причине возвращает нулевой указатель. Проверьте значения, которые вы передаете в это.
  • 0
    Значения, которые я передаю в метод, равны, когда он не выдает исключение
Теги:
gdi+
gdi
system.drawing

2 ответа

1
Лучший ответ
    this.Region = GetRoundedRegion(this.Width, this.Height);

Вы получаете такое исключение, когда происходит утечка программ. Windows позволяет использовать до 10 000 из них, затем он становится грубым и предполагает, что с вашей программой что-то не в порядке. Что-то вы можете увидеть на вкладке "Процессы" Taskmgr.exe. Открыть + Выбрать столбцы и пометить объекты GDI. Могут также включать Ручки и объекты USER. Если это число продолжает расти, пока вы используете свою программу, тогда у вас есть утечка ручек. Kaboom, когда он достигает 10000.

Ваше использование свойства Region - отличный кандидат. Он не должен быть назначен в OnPaint(), который может создать бурю событий красок. Это нужно сделать только один раз, вы должны только назначать его в OnHandleCreated(), поэтому это делается только один раз.

Это само по себе исправит быстрое исключение, которое вы получите. Но убедитесь, что у вас еще нет утечки ручек, вы также несете ответственность за освобождение ручки. Вы должны выровнять DeleteObject() после того, как окно будет удалено. Протестируйте это, написав тестовую программу, которая многократно создает и удаляет элемент управления. И убедитесь, что количество объектов GDI остается стабильным. Вы можете использовать класс .NET Region, поэтому все это автоматически, минус удобство создания закругленного прямоугольника, созданного для вас.

  • 0
    Это, действительно, кажется проблемой, для test ive, установленного в событии рисования, метод deleteObject, и счетчик GDI остается стабильным (действительно ли плохо использовать их обоих в событии рисования? Потому что я создаю и располагаю его каждый onPaint) , Вы говорите, что мне нужен класс региона .net, но я не получу округленную область, как тогда я могу получить округленный элемент управления?
  • 0
    Просто используйте конструктор Region (GraphicsPath). Что требует от вас создания GraphicsPath, который имеет желаемую форму.
0

Прежде чем продолжить, я должен сказать, что я не знаком с библиотекой gdi, так что это предположение в лучшем случае. Я не буду нести ответственность за любой ущерб программному обеспечению, оборудованию, данным или здравомыслию, что приводит к использованию любой информации, представленной ниже.

Значение 0 для p означает, что вызов CreateRoundedRectRgn завершился с ошибкой. Из имени функции кажется, что он создает регион и возвращает дескриптор его местоположения в памяти, поскольку в документации говорится, что вы должны использовать DeleteObject, чтобы удалить область, которую вы больше не используете.

Это предложило бы мне (и, опять же, это только предположение), что любые ресурсы, используемые библиотекой gdi для создания регионов, например, используются (память или адресное пространство), поэтому сбой вызова CreateRegion не выполняется.

У вас есть два варианта: либо не создавайте регионы так часто (то есть один раз при создании элемента управления, а затем, если он перемещается), или используйте DeleteObject для удаления области в конце вашего метода Paint, Это может быть полезно для IDisposable в блоке using.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню