Три метода System.Drawing проявляют медленное рисование или мерцание: решения? или другие варианты? - PullRequest
2 голосов
/ 16 марта 2010

Я немного рисую с помощью System.Drawing, и у меня возникли некоторые проблемы.

Я держу данные в очереди, и я рисую (графически) эти данные в три графических блока

этот метод заполняет графическое поле, затем прокручивает график по горизонтали.

чтобы не рисовать поверх предыдущих рисунков (и постепенно выглядят более грязно), я нашел 2 решения для рисования графика.

  1. Вызов plot.Clear(BACKGOUNDCOLOR) до цикла отрисовки [прокомментированный блок]

хотя это приводит к появлению мерцания со времени, необходимого для выполнения фактического цикла рисования.

  1. вызов plot.DrawLine(channelPen[5], j, 140, j, 0); перед каждой ничьей [прокомментировано]

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

Вот код для справки:

/*plotx.Clear(BACKGOUNDCOLOR)

ploty.Clear(BACKGOUNDCOLOR)

plotz.Clear(BACKGOUNDCOLOR)*/

for (int j = 1; j < 599; j++)
            {
                if (j > RealTimeBuffer.Count - 1) break;

                QueueEntity past = RealTimeBuffer.ElementAt(j - 1);
                QueueEntity current = RealTimeBuffer.ElementAt(j);

                if (j == 1)
                {
                    //plotx.DrawLine(channelPen[5], 0, 140, 0, 0);
                    //ploty.DrawLine(channelPen[5], 0, 140, 0, 0);
                    //plotz.DrawLine(channelPen[5], 0, 140, 0, 0);
                }

                //plotx.DrawLine(channelPen[5], j, 140, j, 0);
                plotx.DrawLine(channelPen[0], j - 1, (((past.accdata.X - 0x7FFF) / 256) + 64), j, (((current.accdata.X - 0x7FFF) / 256) + 64));

                //ploty.DrawLine(channelPen[5], j, 140, j, 0);
                ploty.DrawLine(channelPen[1], j - 1, (((past.accdata.Y - 0x7FFF) / 256) + 64), j, (((current.accdata.Y - 0x7FFF) / 256) + 64));

                //plotz.DrawLine(markerPen, j, 140, j, 0);
                plotz.DrawLine(channelPen[2], j - 1, (((past.accdata.Z - 0x7FFF) / 256) + 94), j, (((current.accdata.Z - 0x7FFF) / 256) + 94));


            }

Есть ли уловки, чтобы избежать этих накладных расходов?

Если бы не было каких-либо других / лучших решений?

РЕДАКТИРОВАТЬ: см. [Окончательное решение] ниже для кода решения

Ответы [ 5 ]

4 голосов
/ 16 марта 2010

PictureBox уже имеет двойную буферизацию. Единственный способ воспринимать мерцание - это когда вы рисуете прямо на экран, а не используете событие Paint. Не ясно, делаете ли вы из своего фрагмента. Буферизация себя с помощью растрового изображения тоже работает, но не так эффективна, как двойная буферизация, реализованная в Windows Forms.

Вызовите метод Invalidate () при изменении данных, сделайте рисование в событии Paint (используя e.Graphics), и он не будет мерцать.

1 голос
/ 16 марта 2010

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

Например:

// create this once for each graph
Bitmap buffer = new Bitmap({width}, {height});

// when the data changes
using (Graphics g = Graphics.FromImage(buffer))
{
    // ... draw using the graphics
}

// draw the buffer on the picture box's image

Вы делаете рисунок в отдельной теме? Сколько раз вы рисуете данные в секунду? Ваша программа будет работать медленно, если вы делаете это в главном потоке или неоднократно рисуете все растровое изображение несколько раз в секунду.

0 голосов
/ 16 марта 2010

[ЗАКЛЮЧИТЕЛЬНОЕ РЕШЕНИЕ]

Использование события рисования даже с дублирующимися циклами было достаточно быстрым!

В конце, вместо того, чтобы дублировать цикл рисования в каждом событии, я использовал первое событие, чтобы также нарисовать два других графика в растровые изображения, а затем на их событии рисования просто нарисовал растровое изображение.

Так что, по сути, окончательное решение было комбинацией многих ваших ответов.

Спасибо, ребята.

private void pictureBoxAccX_Paint(object sender, PaintEventArgs e)
        {
            bufferedploty.Clear(Color.Black);
            bufferedplotz.Clear(Color.Black);           

            for (int j = 1; j < 599; j++)
            {
                if (j > RealTimeBuffer.Count - 1) break;

                QueueEntity past = RealTimeBuffer.ElementAt(j - 1);
                QueueEntity current = RealTimeBuffer.ElementAt(j);

                e.Graphics.DrawLine(channelPen[0], j - 1, (((past.accdata.X - 0x7FFF) / 256) + 64), j, (((current.accdata.X - 0x7FFF) / 256) + 64));
                bufferedploty.DrawLine(channelPen[1], j - 1, (((past.accdata.Y - 0x7FFF) / 256) + 64), j, (((current.accdata.Y - 0x7FFF) / 256) + 64));
                bufferedplotz.DrawLine(channelPen[2], j - 1, (((past.accdata.Z - 0x7FFF) / 256) + 94), j, (((current.accdata.Z - 0x7FFF) / 256) + 94));
            }   
        }


        private void pictureBoxAccY_Paint(object sender, PaintEventArgs e)
        {        
            e.Graphics.DrawImage(BufferedBitMapy, new Point(0, 0));            
        }


        private void pictureBoxAccZ_Paint(object sender, PaintEventArgs e)
        {            
            e.Graphics.DrawImage(BufferedBitMapz, new Point(0, 0));
        }




private void AddAccPoints()
        {
            //Code for putting in New queue data Here...
            pictureBoxAccX.Invalidate();
            pictureBoxAccY.Invalidate();
            pictureBoxAccZ.Invalidate();
        }

РЕДАКТИРОВАТЬ: С помощью этого точного решения аннулирование элементов управления может привести к тому, что планирование событий будет неопределенным и случайным образом прекратит рисование, поскольку создание растрового изображения выполняется в одном из методов события.

См. Здесь: События OnPaint (недействительные), изменяющие порядок выполнения после периода нормальной работы (время выполнения)

0 голосов
/ 16 марта 2010

Создайте подкласс вашего графического блока и включите опцию двойного буфера.

Открытый класс MyBufferedPictureBox Унаследован от System.Windows.Forms.PictureBox

Public Sub New()
    MyBase.New()

    Me.SetStyle(ControlStyles.OptimizedDoubleBuffer, True)
End Sub

Конечный класс

http://msdn.microsoft.com/en-us/library/system.windows.forms.control.setstyle.aspx

0 голосов
/ 16 марта 2010

Я бы использовал двойной буферный подход. Создайте новое растровое изображение в памяти (того же размера, что и график), создайте графический объект этого растрового изображения.

Затем нарисуйте все, что вы хотите на этом объекте.

После завершения рисования создайте другой графический объект из pictureBox и нарисуйте растровое изображение в памяти, используя DrawImage.

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

Надеюсь, это поможет.

...