Двойная буферизация C # - PullRequest
5 голосов
/ 18 июня 2010

Я пытаюсь реализовать следующий метод: void Ball :: DrawOn (Графика г);

Метод должен рисовать все предыдущие местоположения (сохраненные в очереди) мяча и, наконец, текущее местоположение. Я не знаю, имеет ли это значение, но я печатаю предыдущие местоположения, используя g.DrawEllipse (...), и текущее местоположение, используя g.FillEllipse (...).

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

1) System.Windows.Forms.Control.DoubleBuffered = true;

2) SetStyle (ControlStyles.DoubleBuffer | ControlStyles.UserPaint | ControlStyles.AllPaintingInWmPaint, true);

, пытаясь использовать первое, я получаю сообщение об ошибке, объясняющее, что в этом методе свойство DoubleBuffered недоступно из-за его уровня защиты. Пока я не могу понять, как использовать метод SetStyle.

Можно ли вообще удвоить буфер, пока весь доступ , который у меня есть, к графическому объекту, который я получаю в качестве ввода в метод?

Заранее спасибо,

Edit: Я создал следующий класс

namespace doubleBuffer
{
    class BufferedBall : System.Windows.Forms.Form{
        private Ball ball;
        public BufferedBall(Ball ball)
        {
            this.ball = ball;
        }

    public void DrawOn(Graphics g){
        this.DoubleBuffered = true;
        int num = 0;
        Rectangle drawArea1 = new Rectangle(5, 35, 30, 100);
        LinearGradientBrush linearBrush1 =
        new LinearGradientBrush(drawArea1, Color.Green, Color.Orange, LinearGradientMode.Horizontal);
        Rectangle drawArea2 = new Rectangle(5, 35, 30, 100);
        LinearGradientBrush linearBrush2 =
           new LinearGradientBrush(drawArea2, Color.Black, Color.Red, LinearGradientMode.Vertical);
        foreach (PointD point in ball.previousLocations)
        {
            Pen myPen1;
            if (num % 3 == 0)
                myPen1 = new Pen(Color.Yellow, 1F);
            else if (num % 3 == 1)
                myPen1 = new Pen(Color.Green, 2F);
            else
                myPen1 = new Pen(Color.Red, 3F);
            num++;
            myPen1.DashStyle = System.Drawing.Drawing2D.DashStyle.Solid;
            myPen1.StartCap = System.Drawing.Drawing2D.LineCap.RoundAnchor;
            myPen1.EndCap = System.Drawing.Drawing2D.LineCap.AnchorMask;
            g.DrawEllipse(myPen1, (float)(point.X - ball.radius), (float)(point.Y + ball.radius), (float)(2 * ball.radius), (float)(2 * ball.radius));
        }
        if ((ball.Host.ElapsedTime * ball.Host.FPS * 10) % 2 == 0){
            g.FillEllipse(linearBrush1, (float)(ball.Location.X - ball.radius), (float)(ball.Location.Y + ball.radius), (float)(2 * ball.radius), (float)(2 * ball.radius));
        }else{
            g.FillEllipse(linearBrush2, (float)(ball.Location.X - ball.radius), (float)(ball.Location.Y + ball.radius), (float)(2 * ball.radius), (float)(2 * ball.radius));
        }
    }
}

}

и рисунок шара выглядит следующим образом:

new BufferedBall(this).DrawOn(g);

Это то, что вы имели в виду? потому что он все еще мигает?

Ответы [ 5 ]

3 голосов
/ 18 июня 2010
this.DoubleBuffered = true;

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

3 голосов
/ 18 июня 2010

Form класс имеет свойство DoubleBuffered, выставленное как защищенное.http://msdn.microsoft.com/en-us/library/system.windows.forms.control.doublebuffered.aspx но поскольку вы извлекаете форму из Form, вы можете использовать ее.

2 голосов
/ 18 июня 2010

Более простой способ задать стиль для двойной буферизации производных от Control классов - это использовать отражение. Смотрите здесь: http://www.csharp -examples.net / set-doublebuffered /

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

1 голос
/ 18 июня 2010

Вам не нужно устанавливать DoubleBuffered в true каждый раз, когда вы перерисовываете. Это не отключено, когда рисунок закончен. Просто удалите линию из DrawOn и установите ее в конструкторе или конструкторе форм и проверьте результаты. Установка значения в false вызывает значительное мерцание, в то время как установка в true не делает.

Я попробовал ваш код в форме, где таймер вызывает перерисовку каждую миллисекунду и не заметил мерцания, когда DoubleBuffered имеет значение true:

private int yDir = 1,xDir=1;
int step = 1;

private void timer1_Tick(object sender, EventArgs e)
{
    if (ball.Location.Y >= this.Height-50)
        yDir =   -1 ;
    if (ball.Location.X >= this.Width-50) 
        xDir= -1 ;

    ball.MoveBy(xDir*step,yDir*step);
    ball.Host.ElapsedTime++;
    this.Invalidate();
 }

private void DoubleBufferedBall_Paint(object sender, PaintEventArgs e)
{                      
        DrawOn(e.Graphics);
}
0 голосов
/ 18 июня 2010

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

Это руководство, но оно дает вам полный контроль. Я использовал его с некоторым успехом на некоторых моих любимых проектах.

Вы также можете захотеть взглянуть на XNA - это может быть излишним для вашего проекта, но вы можете использовать XNA в WinForms в качестве механизма рендеринга.

...