开发者

How to draw a Moving arrow image in C#

I have to draw a moving Arrow image (using C# code VS2008) between 2 Bars (image). I tried it with two approaches:

  1. Draw arrow figure by joining points. and then keep changing the x,y coordinates.
  2. making an arrow image and then keep changing its position.

The issue is flickering. Whenever I move the arrow image (or redraw the points) nearby images (actually there few other images as Bars are there) flickers. I tried to call invalidate(rect) thinking it will redraw the given rectangle only but still as soon the arrow image crosses these bars, everything flickers. which doesn't look good. how can I move this arrow image in a smooth fashion. Pls. suggest. Or should I adopt another approach?

// Code: **

public partial class Form1 : Form { private Bitmap bitmapAntenna; private Bitmap bitmapArrow;

public Form1()
{
    bitmapAntenna = new Bitmap("D:\\AntennaBar.JPG");
    bitmapArrow = new Bitmap("D:\\Arrow.JPG");
}

private void DrawAntennaImages(int antennaNo)
{
    Graphics grph = this.CreateGraphics();
    if (1 == antennaNo)
    {
        grph.DrawImage(bitmapAntenna, new RectangleF(350, 300, bitmapAntenna.Width*(1.00F), bitmapAntenna.Height*(1.00F))) ;
    }
    else
        grph.DrawImage(AntennaImage, new Point(550, 300));
}

private void DrawArrowImages(int X)
{
    Graphics grph = this.CreateGraphics();
    grph.DrawImage(bitmapArrow, new Point(380 + X, 350));
}

private void PaintHandler(Object sender, System.Windows.Forms.PaintEventArgs e)
{
    DrawAntennaImages(1);
    DrawAntennaImages(2);
}

private void button_Click(object sender, EventArgs e)
{开发者_开发问答
    for (int i = 1; i < 40; i++)
    {
        //  Note: first draw antenna 1 image, arrow image then antenna 2 image so that arrow will overlap
        //  only antenna 1 image only.

        DrawAntennaImages(1);       //  Draw Antenn 1 image
        DrawArrowImages(i * 2);     //  Draw Arrow image
        DrawAntennaImages(2);       //  Draw Antenn 2 image

        System.Threading.Thread.Sleep(25);  //  Sleep before drawing next time ..
    }
    this.Invalidate(); // If I don't call this, arrow image does not elope after last draw
}

}

// In designer

this.Paint += new System.Windows.Forms.PaintEventHandler(this.PaintHandler);

//Code *

Thanks RPS


Just turn on double buffering for the form

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

or for the control you draw on.

myCanvasControl.DoubleBuffered = true;

Here is some more information about double buffering in windows forms and GDI+.

Oh, and by the way: These kind of problems do not exist in WPF. When it comes to graphics quality and ease of use (for straightforward things like what you are doing) WPF is much superior to windows forms and GDI+.

This is how you could draw a moving arror in WPF/XAML:

<Canvas>
    <Canvas.Resources>
        <Storyboard x:Key="OnLoaded1">
            <DoubleAnimationUsingKeyFrames RepeatBehavior="Forever" Storyboard.TargetProperty="(Canvas.Left)" Storyboard.TargetName="blockArrow">
                <EasingDoubleKeyFrame KeyTime="0:0:6" Value="500"/>
            </DoubleAnimationUsingKeyFrames>
        </Storyboard>
    </Canvas.Resources>
    <ed:BlockArrow x:Name="blockArrow" Stroke="Black" Width="100" Height="50" Canvas.Left="0" Canvas.Top="200"/>
</Canvas>


I am assuming WinForms here:

Have you tried using double buffering?

You could try to implement your own double buffering.

Do not expect miracles here; WinForms was never meant to do stuff like this.


If you have a PictureBox try setting DoubleBuffering = true. If this flickering persists, draw everything onto a Bitmap before drawing the Bitmap on the screen.


We do animation in WinForms and don't suffer from any flickering with our technique, which is something like this:

  • Create a System.Windows.Forms.Timer object. Set the interval for 25 frames per second: timer.Interval = 1000/25; Add a callback method to the Tick event: timer.Tick += new EventHandler(animateCallback)
  • animateCallback should update the coordinates of your Arrow instance and call Invalidate() to let the .NET graphics system call your control's Paint method.

Using the System.Windows.Forms.Timer class is crucial to avoid flicker. This timer runs in the UI Thread. That means, the callback you get is in the UI Thread. So the system will not do any drawing while you are updating your arrow coordinates in your animateCallback method.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜