0

Here is my code:

    int i = 0;
    public Form1()
    {
        InitializeComponent();
    }


    Graphics gObject;
    private void panel1_Paint(object sender, PaintEventArgs e)
    {
        gObject = panel1.CreateGraphics();
    }

    void DrawLines(Graphics gObject, Pen pPen)
    {
        Point pPoint1 = new Point(this.Bounds.Width / 2, 0);
        Point pPoint2 = new Point(this.Bounds.Width / 2 - this.Bounds.Width / 4, 0);
        Point pPoint3 = new Point(this.Bounds.Width / 2 + this.Bounds.Width / 4, 0);
        Point pPoint1a = new Point(this.Bounds.Width / 2, 1000);
        Point pPoint2a = new Point(this.Bounds.Width / 2 - this.Bounds.Width / 4, 1000);
        Point pPoint3a = new Point(this.Bounds.Width / 2 + this.Bounds.Width / 4, 1000);
        gObject.DrawLine(pPen, pPoint1, pPoint1a);
        gObject.DrawLine(pPen, pPoint2, pPoint2a);
        gObject.DrawLine(pPen, pPoint3, pPoint3a);
    }

    void DrawSlots(Graphics gObject, Pen pPen)
    {
        int WindowWidth = this.Bounds.Width;
        int WindowHeight = this.Bounds.Height;
        int RectHeight, RectWidth;
        RectHeight = 550;
        RectWidth = 350;

        Rectangle Slot1 = new Rectangle(WindowWidth / 2 - WindowWidth / 4 - RectWidth / 2+i, WindowHeight / 2 - RectHeight / 2, RectWidth, RectHeight);
        Rectangle Slot2 = new Rectangle(WindowWidth / 2 - RectWidth / 2, WindowHeight / 2 - RectHeight / 2, RectWidth, RectHeight);
        Rectangle Slot3 = new Rectangle(WindowWidth / 2 + WindowWidth / 4 - RectWidth / 2, WindowHeight / 2 - RectHeight / 2, RectWidth, RectHeight);

        gObject.DrawRectangle(pPen, Slot1);
        gObject.DrawRectangle(pPen, Slot2);
        gObject.DrawRectangle(pPen, Slot3);
    }

    private void timer1_Tick(object sender, EventArgs e)
    {
        i++;
        Brush red = new SolidBrush(Color.Red);
        Pen redPen = new Pen(red, 1);

        DrawSlots(gObject, redPen);

        this.Refresh();
    }

My issue is that every time Refresh is called, my rectangles blink, but never update. The timer is set to tick every 500ms. I have check to make sure the numbers are updating but I cant see to find out why the rectangles are not movie, and why the graphics are blinking.

Any help would be greatly appreciated, I have searched high and low for the answers

marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
BlueBaroo
  • 131
  • 2
  • 15
  • Use a subclass of Panel with DoubleBuffering=true or go for a PictureBox! - Also go for Mehrzad's advice! – TaW May 01 '15 at 19:06
  • So I went for a picture box, but it seems to be lagging a bit. Is there a way to turn on Vsync for a picture box? The simple animations I have seem to lag on my computer – BlueBaroo May 07 '15 at 16:41

2 Answers2

1

You are drawing in wrong way. Drawings should be done in Paint event on the panel not in Timer_Tick event. You only should call Invalidate method of the panel to force a repaint. Try this:

int i = 0;
public Form1() {
    InitializeComponent();
}
private void panel1_Paint(object sender, PaintEventArgs e) {
    DrawSlots(e.Graphics, Pens.Red);
}

void DrawLines(Graphics gObject, Pen pPen) {
    Point pPoint1 = new Point(this.Bounds.Width / 2, 0);
    Point pPoint2 = new Point(this.Bounds.Width / 2 - this.Bounds.Width / 4, 0);
    Point pPoint3 = new Point(this.Bounds.Width / 2 + this.Bounds.Width / 4, 0);
    Point pPoint1a = new Point(this.Bounds.Width / 2, 1000);
    Point pPoint2a = new Point(this.Bounds.Width / 2 - this.Bounds.Width / 4, 1000);
    Point pPoint3a = new Point(this.Bounds.Width / 2 + this.Bounds.Width / 4, 1000);
    gObject.DrawLine(pPen, pPoint1, pPoint1a);
    gObject.DrawLine(pPen, pPoint2, pPoint2a);
    gObject.DrawLine(pPen, pPoint3, pPoint3a);
}

void DrawSlots(Graphics gObject, Pen pPen) {
    int WindowWidth = this.Bounds.Width;
    int WindowHeight = this.Bounds.Height;
    int RectHeight, RectWidth;
    RectHeight = 550;
    RectWidth = 350;

    Rectangle Slot1 = new Rectangle(WindowWidth / 2 - WindowWidth / 4 - RectWidth / 2 + i, WindowHeight / 2 - RectHeight / 2, RectWidth, RectHeight);
    Rectangle Slot2 = new Rectangle(WindowWidth / 2 - RectWidth / 2, WindowHeight / 2 - RectHeight / 2, RectWidth, RectHeight);
    Rectangle Slot3 = new Rectangle(WindowWidth / 2 + WindowWidth / 4 - RectWidth / 2, WindowHeight / 2 - RectHeight / 2, RectWidth, RectHeight);

    gObject.DrawRectangle(pPen, Slot1);
    gObject.DrawRectangle(pPen, Slot2);
    gObject.DrawRectangle(pPen, Slot3);
}

private void timer1_Tick(object sender, EventArgs e) {
    i++;
    this.panel1.Invalidate();
}

Edit:

The blinking thing is result of re-painting whole control on each Invalidate call (in the timer). When a control repaints itself, the OnPaintBackground method paints background of the control and then in the paint event handler, your drawing work happens again.

To avoid this problem, you need to invalidate ONLY the region that needs to be re-painted. You can use another overload of Invalidate that receives an region, and pass the invalid region to the it.

Mehrzad Chehraz
  • 5,092
  • 2
  • 17
  • 28
  • I just tried this but it results in the same blinking effect. Is there any property on the Panel or Timer itself that has to be toggled to make it not blink? – BlueBaroo May 01 '15 at 18:17
  • So I tried using the Overload of Invalidate taking in a Rectangle. It only updates the rectangle I gave it but it still blinks and doesnt update the whole rectangle – BlueBaroo May 01 '15 at 18:40
  • You need l calculate exactly the region that needs to be updated (changed since previous tick) so that you make sure even a single pixel won't be redrawn in the same place. It usually gets tricky and you need to use the Region class to compute the exact region. If you redraw a pixel in the same place it was before, you will face a blink in that pixel because OnPaintBackground fills the -red- pixel with BackColor and then the pixel get drawn to red. – Mehrzad Chehraz May 01 '15 at 18:46
0

I think you are looking for suspendLayout and resumeLayout. Generally they stop most flickering. Just wrap your event before you do your UI updates before and after and that generally does the trick.

private void panel1_Paint(object sender, PaintEventArgs e) {
// Suspend the form layout and do your activites 
   this.SuspendLayout();
    DrawSlots(e.Graphics, Pens.Red);

   this.ResumeLayout();
}
DoomVroom
  • 330
  • 2
  • 14
  • I just tried this. It is still acting the same. Right now the program in running in full screen and I am trying to make a slots game, if that helps this process at all – BlueBaroo May 01 '15 at 18:43
  • I tried using Refresh() and it actually stopped most of the flickering using this method. So you know how to kill all of the blinking? This will need to look as smooth as possible – BlueBaroo May 01 '15 at 18:45
  • I generally work with windows forms to create Interfaces for buttons. If it is a smooth animation, you are going to probably need to learn about things like buffering. http://stackoverflow.com/questions/188349/simple-animation-using-c-windows-forms – DoomVroom May 01 '15 at 19:16