OnPaint в winform - .NET Compact Framework 3.5 - PullRequest
2 голосов
/ 19 марта 2012

В настоящее время я работаю над изогнутым индикатором выполнения в проекте смарт-устройства. Я переопределяю функцию OnPaint.

В функции Override OnPaint () я рисую изогнутый индикатор выполнения темно-серым цветом и рисую часть индикатора выполнения желтым цветом, чтобы отразить изменяющееся значение (например, 30%) индикатора выполнения. Однако, когда значение постоянно меняется, я вижу, что часть цвета индикатора выполнения меняется на желтый. Однако сам по себе изогнутый индикатор выполнения также перерисовывается. Кто-нибудь знает способ, как избежать перерисовки оригинального изогнутого индикатора выполнения при изменении значения? Таким образом, когда значение изменяется, оно перерисовывает только часть индикатора выполнения желтым цветом, а не оригинальную индикатор выполнения серым цветом. Вот код, который я использую в функции OnPaint.

protected override void OnPaint(PaintEventArgs e)
        {
            gx = e.Graphics;
// Draw the original curved progress bar
            int intPosition1 = m_NumberOfSpoke;

            for (int intCounter1 = 0; intCounter1 < m_NumberOfSpoke; intCounter1++)
            {
                intPosition1 = intPosition1 % m_NumberOfSpoke;
                DrawLine(e.Graphics,
                         GetCoordinate(m_CenterPoint, m_InnerCircleRadius, m_Angles[intPosition1]),
                         GetCoordinate(m_CenterPoint, m_OuterCircleRadius, m_Angles[intPosition1]),
                         Color.DarkGray, m_SpokeThickness);
                intPosition1++;
            }

     // Draw a part of the progress bar to reflect the changing current value(such as 30%)
   int intPosition = CurrentValue;

                for (int intCounter1 = 0; intCounter1 < CurrentValue; intCounter1++)
                {
                    intPosition = intPosition % CurrentValue;
                    DrawLine(gx,
                             GetCoordinate(m_CenterPoint, m_InnerCircleRadius, m_Angles[intPosition]),
                             GetCoordinate(m_CenterPoint, m_OuterCircleRadius, m_Angles[intPosition]),
                             Color.Yellow, m_SpokeThickness);
                    intPosition++;
                }

        base.OnPaint(e);



        }

Я пытался использовать Override OnBackgroundPaint, чтобы нарисовать оригинальный изогнутый индикатор выполнения в качестве фона, чтобы избежать его перерисовки в OnPaint, но он не работает. Я не вижу ничего, когда форма загружена. Есть идеи?

Спасибо за любую помощь заранее.

С уважением

1 Ответ

3 голосов
/ 19 марта 2012

Это загрузка вызовов DrawLine к реальному экрану, и вполне вероятно, что это вызовет мерцание. Вы должны удвоить буфер, создав обратный буфер, сделав все, что вы рисуете на нем, затем перетащите его на экран одним вызовом DrawBitmap по следующим строкам:

protected override void OnPaint(PaintEventArgs e)
{
    using(var buffer = new Bitmap(this.Width, this.Height))
    using(var gx = Graphics.FromImage(buffer))
    {
        // for loops to draw to gx
        ....

        e.Graphics.DrawBitmap(buffer, ...);
    }

}

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

Bitmap m_buffer;
Gramphic m_gx;

protected override void OnPaint(PaintEventArgs e)
{
    if(m_buffer == null)
    {
        m_buffer = new Bitmap(this.Width, this.Height))
        m_gx = Graphics.FromImage(buffer))
    }

    // clear the backbuffer with a FillRect

    // for loops to draw to m_gx
    ....

    e.Graphics.DrawBitmap(m_buffer, ...);
}

Вероятно, я бы даже пошел на шаг дальше, если серая часть элемента управления всегда одинакова и выполняла бы «тройной буфер», сохраняя кэшированную версию изображения с нарисованным серым, затем в OnPaint, blit что к графике, нарисуйте желтый, а затем блин на экран.

Bitmap m_buffer;
Bitmap m_backimage;
Gramphic m_gx;

protected override void OnPaint(PaintEventArgs e)
{
    if(m_buffer == null)
    {
        m_backimage = new Bitmap(this.Width, this.Height);
        var g = Graphics.FromImage(m_backImage);
        // for loop to draw the grey stuff to g
        ....

        m_buffer = new Bitmap(this.Width, this.Height))
        m_gx = Graphics.FromImage(buffer))
    }

    m_gx.DrawImage(m_backImage);

    // for loop to draw *just the yellow* to m_gx
    ....

    e.Graphics.DrawBitmap(m_buffer, ...);
}

Вам, вероятно, придется переопределить OnResize и некоторые другие вещи, а также расширить Dispose для очистки этих объектов GDI уровня члена, но perf будет намного лучше, и он не будет мерцать.

...