why is rendering turning form black

745 views Asked by At

I'm using an eye tracker to display eye movements on a form. The movements have been flickering a lot so I found out I can use BufferedGraphics which all works fine except when the eye movement starts it turns the form from the original colour to black. This is the code. Hopefully someone can help!

private void button2_Click(object sender, EventArgs e)
{
    var host = new Host();
    var gazeStream = host.Streams.CreateGazePointDataStream();
    gazeStream.GazePoint((x, y, ts) 
         => drawCircle(new PointF((float)x, (float)y)));
}

delegate void SetCallback(PointF point);

private void drawCircle(PointF point)
{
    float x = point.X;
    float y = point.Y;

    if (this.InvokeRequired)
    {
        SetCallback d = new SetCallback(drawCircle);
        this.Invoke(d, new object[] { point });
    }
    else
    {
        SolidBrush semiTransBrush = new SolidBrush(Color.Coral);
        Pen pen = new Pen(Color.Aquamarine, 2);

        BufferedGraphicsContext currentContext;
        BufferedGraphics myBuffer;
        // Gets a reference to the current BufferedGraphicsContext
        currentContext = BufferedGraphicsManager.Current;
        // Creates a BufferedGraphics instance associated with Form1, and with 
        // dimensions the same size as the drawing surface of Form1.
        myBuffer = currentContext.Allocate(this.CreateGraphics(),this.DisplayRectangle);
        myBuffer.Graphics.DrawEllipse(pen, x, y, 100, 100);
        myBuffer.Graphics.FillEllipse(semiTransBrush, x, y, 100, 100);


        // Renders the contents of the buffer to the specified drawing surface.
        myBuffer.Render(this.CreateGraphics());

        myBuffer.Dispose();
    }

enter image description here

You can see in the image that the circle appears behind the controls which seems like the form is gone?

1

There are 1 answers

3
György Kőszeg On BEST ANSWER

When you allocate the buffer, it creates a compatible rendering surface with the graphics you provided. But it will not copy it or anything so if you just paint a single circle, the remaining parts remain black.

BufferedGraphics really can help you to avoid flickering in special cases (eg. when system double buffering must be disabled for some reason), but here this is an overkill.

So the key is just enabling double buffering and do every paint in the Paint event (or OnPaint method). In your code you do immediate paint, which always flickers. Instead, you should just invalidate the form and let the system do a regular repaint session, which can use double buffering if you wish.

Into the constructor:

SetStyle(ControlStyles.OptimizedDoubleBuffer | ControlStyles.DoubleBuffer | ControlStyles.AllPaintingInWmPaint, true);

Then modify the click event:

private PointF lastGazePoint;

private void button2_Click(object sender, EventArgs e)
{
    var host = new Host();
    var gazeStream = host.Streams.CreateGazePointDataStream();
    gazeStream.GazePoint((x, y, ts) => 
        {
            lastGazePoint = new PointF((float)x, (float)y);
            Invalidate();
        });
 }

The painting itself:

protected override void OnPaint(PaintEventArgs e)
{
    base.OnPaint(e);
    DrawCircle(e.Graphics, lastGazePoint.X, lastGazePoint.Y);
}

And finally, modify DrawCircle to use the Graphics from PaintEventArgs:

private void DrawCircle(Graphics g, float x, float y)
{
    using (Brush semiTransBrush = new SolidBrush(Color.Coral))
    {
        using (Pen pen = new Pen(Color.Aquamarine, 2))
        {
            g.DrawEllipse(pen, x, y, 100, 100);
            g.FillEllipse(semiTransBrush, x, y, 100, 100);
        }        
    }        
}