(.NET / C # / winforms) Артефактирование при рисовании на форме с графикой - PullRequest
1 голос
/ 16 апреля 2009

Моя цель - переместить визуальные элементы, нарисованные с помощью методов графического объекта, по форме без мерцания и артефактов (в .NET 3.5). Я могу успешно добиться движения без мерцания, используя либо автоматическую двойную буферизацию (устанавливая свойство DoubleBuffered формы в значение true), либо самостоятельно создавая буфер. Я, однако, изо всех сил пытаюсь найти способ использовать любой метод без четко видимых артефактов.

При использовании автоматической двойной буферизации эффект разрыва страницы очевиден. Похоже, что резервный буфер медленно, постепенно копируется в форму, сверху вниз, после трех обновлений моего 60 Гц ЖК-дисплея.

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

public partial class Form1 : Form {
    int x;
    Bitmap buffer;

    public Form1() {
        InitializeComponent();
        buffer = new Bitmap(Width, Height);
    }

    private void Form1_Paint(object sender, PaintEventArgs e) {
        Graphics g = Graphics.FromImage(buffer);
        g.Clear(Color.FromArgb(255, 255, 255));
        g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
        g.FillRectangle(Brushes.Blue, x, 0, 100, 500);
        e.Graphics.DrawImageUnscaled(buffer, 0, 0);
    }

    protected override void OnPaintBackground(PaintEventArgs pevent) {
        //Don't allow the background to paint
    }

    private void Form1_KeyDown(object sender, KeyEventArgs e) {
        const int scrollSpeed = 20;
        if(e.KeyData == Keys.Left) {
            x -= scrollSpeed;
            Refresh();
        }
        else {
            if(e.KeyData == Keys.Right) {
                x += scrollSpeed;
                Refresh();
            }
        }
    }
}

if (другие способны воспроизвести эффект) {
Я делаю что-то не так, возможно, что-то вызывает
тип расы в коде окраски или
это просто поведение среды выполнения, которую я должен
жить с?
}
еще {
Может быть, это особенность моей видеокарты или
глючил драйвер дисплея?
}

Ответы [ 4 ]

1 голос
/ 16 апреля 2009

Всякий раз, когда я выполнял двойную буферизацию, я старался не иметь кода рендеринга внутри события Paint; единственным кодом в событии было копирование из буфера на экран.

Попробуйте переместить код рендеринга в его собственную функцию, а затем сделать недействительной область (в данном случае форму):

RenderScene()
Invalidate()

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

1 голос
/ 16 апреля 2009

Может быть важно знать, что видеокарты, ускоряющие 2D-операции, обычно ускоряют GDI, а не GDI +. Я думаю, что использование растрового изображения GDI и его рисование напрямую с использованием методов GDI (например, через p / invoke) ускорило бы процесс.

0 голосов
/ 16 апреля 2009

Помимо того, что overslacked сказал использовать Invalidate, вам также не нужно сглаживание для заполнения прямоугольника без применения преобразования.

0 голосов
/ 16 апреля 2009

На самом деле это выглядит "нормально", когда я нажимаю и отпускаю клавишу (хотя, если вы удерживаете клавишу нажатой, возникает небольшой разрыв, который разрешается при следующем движении).

Я на Vista с ATI x1300 и Intel e6400. Возможно, скорость обработки или ваша видеокарта являются проблемой?

edit: Сказанное выше, я согласен с другими и скажу, что GDI + - это не тот путь, если вы ищете быстрый. DirectX или использование Windows API могут быть подходящими.

...