Question

My code isn't working! I've commented out my problems with /**'s.
I have a OutOfMemory exception when I close the pendulum form as I am passing an IntPtr handle and it becomes to large.
I also have a problem making the pendulum swing and loose velocity each time. Is their a problem in my theory or have I done something stupid.
Below is the code to my pendulum class:

using System.Drawing; //new
using System.Windows.Forms; //new

  class Pendulum
{
    int length = 50;
    double angle = Math.PI /2;
    double aAcc = -9.81;
    double aVel = 0;
    double gravity = 0.1;
    double mass = 0.2;
    Timer timer;

    public Pendulum(int frmWidth, int frmHeight, IntPtr handle)
    {
        timer = new Timer() { Interval = 30 };

        timer.Tick += delegate(object sender, EventArgs e)
        {
            int originX = frmWidth / 2;
            int originY = 0;
            int bobX; // = frmWidth / 2;
            int bobY; // = (int)length;

            //to be relative to origin we go:
            bobX = originX + (int)(Math.Sin(angle) * length);
            bobY = originY +  (int)(Math.Cos(angle) * length);

            aAcc = -9.81 / length * Math.Sin(angle);

            aVel += aAcc * gravity * mass;
            angle += aVel * gravity; //angle += aVel;
            //aVel = aVel -0.09; /** SPEED UP DRAMATICALLY! SPINS WEIRDLY! **/
            DrawPendulum(originX,originY,bobX,bobY,frmWidth,frmHeight, handle);

        };

        timer.Start();
    }

    public void DrawPendulum(int originX, int originY, int bobX, int bobY, int frmWidth, int frmHeight, IntPtr handle)
    {
        using(Bitmap dblBuffer = new Bitmap(frmWidth, frmHeight))
        using(Graphics g = Graphics.FromImage(dblBuffer))
        using(Graphics f = Graphics.FromHwnd(handle))
        {

        g.DrawLine(Pens.Black, originX, originY, bobX, bobY);
        g.FillEllipse(Brushes.Blue, bobX - 8, bobY, 20, 20); //-8 for tidyness!

        f.Clear(Color.White);
        f.DrawImage(dblBuffer, new Point(0, 0));

        }
    }
}

 public partial class frmPendulum : Form
{
    Pendulum p;
    public frmPendulum()
    {
        frmLogin frm = new frmLogin();
        frm.Close();

        int frmWidth = this.Width;
        int frmHeight = this.Height;
        IntPtr Handle = this.Handle;

         p = new Pendulum(frmWidth, frmHeight, Handle);

        InitializeComponent();
    }

    private void frmPendulum_Load(object sender, EventArgs e)
    {

    }

  public void TimerDispose()
        {
            timer.Dispose();
        }
    }

public partial class frmLogin : Form
    {
        public frmLogin()
    {
        InitializeComponent();
    }

    private void frmLogin_Load(object sender, EventArgs e)
    {

    }

    private void btnSubmit_Click(object sender, EventArgs e)
    {
        frmPendulum f = new frmPendulum();
        f.Show();
        //this.Hide();
    }
}

EDIT: To try and dispose the timer I've made Pendulum p global so that it can be used to run the new method I've put inside the pendulum class below:

    public void TimerDispose()
    {
        timer.Dispose();
    }

This also meant making the timer global. However the OutOfMemory exception still occurs. All code is its current state above.

Was it helpful?

Solution

What a mess....

Handle the Paint() event of frmPendulum() and pass its e.Graphics to DrawPendulum().
frmPendulum should have its own Timer that simply refreshes itself.

In Pendulum, draw directly to the passed Graphics. Get rid of the Bitmap and Handle code. The variables should all be at class level so they can be accessed in DrawPendulum(). Pendulum should not draw itself in the Tick() event.

So it should look more like this:

public partial class frmPendulum : Form
{

    private Timer timer;
    private Pendulum p = null;

    public frmPendulum()
    {
        InitializeComponent();

        this.Shown += new EventHandler(frmPendulum_Shown);
        this.Paint += new PaintEventHandler(frmPendulum_Paint);
    }

    void frmPendulum_Shown(object sender, EventArgs e)
    {
        p = new Pendulum(this.ClientRectangle.Width, this.ClientRectangle.Height);
        timer = new Timer() { Interval = 100 };
        timer.Tick += delegate(object s2, EventArgs e2)
        {
            this.Refresh();
        };
        timer.Start();
    }

    void frmPendulum_Paint(object sender, PaintEventArgs e)
    {
        if (p != null)
        {
            p.DrawPendulum(e.Graphics);
        }
    }

}

public class Pendulum
{

    int length = 50;
    double angle = Math.PI / 2;
    double aAcc = -9.81;
    double aVel = 0;
    double gravity = 0.1;
    double mass = 0.2;

    int originX = 0;
    int originY = 0;
    int bobX; // = frmWidth / 2;
    int bobY; // = (int)length;

    Timer timer;

    public Pendulum(int frmWidth, int frmHeight)
    {
        timer = new Timer() { Interval = 50 };

        timer.Tick += delegate(object sender, EventArgs e)
        {
            originX = frmWidth / 2;
            originY = 0;

            //to be relative to origin we go:
            bobX = originX + (int)(Math.Sin(angle) * length);
            bobY = originY + (int)(Math.Cos(angle) * length);

            aAcc = -9.81 / length * Math.Sin(angle);

            aVel += aAcc * gravity * mass;
            angle += aVel * gravity; 
        };

        timer.Start();
    }

    public void DrawPendulum(Graphics G)
    {
        G.DrawLine(Pens.Black, originX, originY, bobX, bobY);
        G.FillEllipse(Brushes.Blue, bobX - 8, bobY, 20, 20); //-8 for tidyness!
    }

}

enter image description here

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top