Мерцание графики C#

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

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

namespace GraphicsTest
{
    public partial class Form1 : Form
    {
        int xFirst, yFirst;
        Bitmap bm = new Bitmap(1000, 1000);
        Graphics bmG;
        Graphics xG;
        Pen pen = new Pen(Color.Black, 1);
        bool draw = false;

        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            bmG = Graphics.FromImage(bm);
            xG = this.CreateGraphics();
            bmG.Clear(Color.White);
        }

        private void Form1_MouseDown(object sender, MouseEventArgs e)
        {
            xFirst = e.X;
            yFirst = e.Y;
            draw = true;
        }

        private void Form1_MouseUp(object sender, MouseEventArgs e)
        {
            bmG.DrawLine(pen, xFirst, yFirst, e.X, e.Y);
            draw = false;
            xG.DrawImage(bm, 0, 0);
        }

        private void Form1_MouseMove(object sender, MouseEventArgs e)
        {
            if (draw)
            {
                xG.DrawImage(bm, 0, 0);
                xG.DrawLine(pen, xFirst, yFirst, e.X, e.Y);
            }
        }

        private void Form1_Paint(object sender, PaintEventArgs e)
        {
            xG.DrawImage(bm, 0, 0);
        }
    }
}
10
задан OregonGhost 9 April 2010 в 16:17
поделиться

3 ответа

Во-первых, не используйте CreateGraphics () , если в этом нет крайней необходимости. Привяжите обработчик событий к OnPaint и вызовите Invalidate () , если вы хотите обновить поверхность.

Если вы не хотите, чтобы он мерцал, вам нужно удвоить буфер на поверхности для рисования. Самый простой способ сделать это - установить для свойства формы DoubleBuffered значение True.

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

В коде:

public partial class Form1 : Form
    {
    int xFirst, yFirst;
    Bitmap bm = new Bitmap(1000, 1000);
    Graphics bmG;
    Pen pen = new Pen(Color.Black, 1);
    bool draw = false;

    public Form1()
    {
        InitializeComponent();
    }

    private void Form1_Load(object sender, EventArgs e)
    {
        bmG = Graphics.FromImage(bm);
        bmG.Clear(Color.White);
    }

    private void Form1_MouseDown(object sender, MouseEventArgs e)
    {
        xFirst = e.X;
        yFirst = e.Y;
        draw = true;
    }

    private void Form1_MouseUp(object sender, MouseEventArgs e)
    {
        bmG.DrawLine(pen, xFirst, yFirst, e.X, e.Y);
        draw = false;
        Invalidate();
    }

    private void Form1_MouseMove(object sender, MouseEventArgs e)
    {
        if (draw)
        {
            Invalidate();
        }
    }

    private void Form1_Paint(object sender, PaintEventArgs e)
    {
        if (draw) {
            e.Graphics.DrawImage(bm, 0, 0);
            e.Graphics.DrawLine(pen, xFirst, yFirst, e.X, e.Y);
        } else {
            e.Graphics.DrawImage(bm, 0, 0);
        }
    }
}

Изменить:

Другая проблема, вы создаете частного члена Pen . Перья (и кисти, а также многие объекты GDI +) представляют собой дескрипторы неуправляемых объектов, которые необходимо удалить, иначе ваша программа будет протекать. Либо заключите их в , используя операторы (предпочтительный и безопасный способ), либо явно удалите их с помощью метода формы Dispose .

В качестве альтернативы в System.Drawing вы можете получить доступ к некоторым предварительно созданным перьям и кистям, которые не нужно (и не следует) удалять. Используйте их как:

    private void Form1_Paint(object sender, PaintEventArgs e)
    {
        if (draw) {
            e.Graphics.DrawImage(bm, 0, 0);
            e.Graphics.DrawLine(Pens.Black, xFirst, yFirst, e.X, e.Y);
        } else {
            e.Graphics.DrawImage(bm, 0, 0);
        }
    }
25
ответ дан 3 December 2019 в 14:18
поделиться

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

Лучшее решение этой проблемы - двойная буферизация. Что вы делаете, так это рисуете все изображение в растровое изображение «за кадром» и показываете его на экране только после завершения. Поскольку вы всегда показываете только законченное изображение, эффект мерцания отсутствует. Вы должны просто установить this.DoubleBuffered = true, чтобы WinForms выполнял всю тяжелую работу за вас.

NB: на самом деле вам не следует рисовать за пределами обработчика рисования - в идеале вы должны сделать Invalidate () область, которую нужно перерисовать, а затем обработчик рисования перерисует только эту область (с любыми наложенными линиями и т. Д. По мере необходимости) .

8
ответ дан 3 December 2019 в 14:18
поделиться

Исправленный и рабочий код.

public partial class Form1 : Form
{
    int x1, y1, x2, y2;
    bool drag = false;

    Bitmap bm = new Bitmap(1000, 1000);
    Graphics bmg;


    public Form1()
    {
        InitializeComponent();
    }

    private void Form1_Load(object sender, EventArgs e)
    {
        bmg = Graphics.FromImage(bm);
    }

    private void pictureBox_MouseDown(object sender, MouseEventArgs e)
    {
        drag = true;
        x1 = e.X;
        y1 = e.Y;
    }

    private void pictureBox_MouseUp(object sender, MouseEventArgs e)
    {
        drag = false;

        bmg.DrawLine(Pens.Black, x1, y1, e.X, e.Y);
        pictureBox.Invalidate();
    }

    private void pictureBox_MouseMove(object sender, MouseEventArgs e)
    {
        if (drag)
        {
            x2 = e.X;
            y2 = e.Y;
            pictureBox.Invalidate();
        }
    }

    private void pictureBox_Paint(object sender, PaintEventArgs e)
    {
        if (drag) {
            e.Graphics.DrawImage(bm, 0, 0);
            e.Graphics.DrawLine(Pens.Black, x1, y1, x2, y2);            
        }
        else {
            e.Graphics.DrawImage(bm, 0, 0);
        }
    }
}
2
ответ дан 3 December 2019 в 14:18
поделиться
Другие вопросы по тегам:

Похожие вопросы: