Ripple.NET: A Windows Forms Demo

Finally, in the OnPaint Event Handler I clear the Form and step through the rippleLIst drawing each of the RippleObjs in it that has a location Point that's not Empty.

  1. I started off by defining a "RippleObj" class which can be found at the bottom of the source code (lines 140-160). Each Ripple we create in the application will be of this type.

  2. Next I create an array of 255 RippleObj objects called rippleList.

  3. Override 3 of the Form's Mouse Event Handlers (OnMouseDown, OnMouseMove and OnMouseUp). When the user clicks the left mouse button down I set the first RippleObj in rippleList to the location of the mouse. Then while the mouse button is still down I increment my counter and set the next RippleObj to the new mouse location. And I continue to do this until the user lets go of the mouse button.

  4. I add a Timer to the Form named timer1. I then assign an Event Handler to the Timer which monitors ticks. At every set interval the Timer1OnClick is called. From there is where I check to see if the mouse is still down and add the Ripple if so.

  5. Finally, in the OnPaint Event Handler I clear the Form and step through the rippleLIst drawing each of the RippleObjs in it that has a location Point that's not Empty. Everytime a Ripple is drawn I increment it's radius so the next time it's drawn larger. The size of the radius also determines the opacity of the Pen that's used to draw the brush. After a Ripple has gone all the way down to completely transparent (0% opaque) it's location is set to Empty so it will no longer draw.

// A simple ripple test.
// I make no warrantees as to it's stability. Use at your own risk.
// If you make any improvements on it please send them to me.
// Written by: James O'Reilly, SynergyMedia, Inc.
// To compile at the console:
// csc.exe /out:.\Ripple.exe /t:exe /r:System.dll Ripple.cs

using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;
namespace SynergyMediaInc
class Ripple: Form
RippleObj[] rippleList =
new RippleObj[254];
int ripplePntr = 0;
bool mouseDown = false;
Point ptMouse = Point.Empty;
Font font1;
private Timer timer1 = new Timer();
private long ticks = 0;
// if you don't know i'm not telling
public static void Main()
new Ripple());
public Ripple()
Text = "Ripple";
BackColor = Color.Blue;
ForeColor = Color.White;
ClientSize += ClientSize;
// Double the client area.
font1 = new Font("Times New Roman", 144);
// reduce flicker
SetStyle(ControlStyles.UserPaint, true);
// we need a timer to animate
timer1.Interval = 50;
timer1.Tick +=
new System.EventHandler(Timer1OnTick);
// add a new ripple to the list and flag the mouse as down
protected override void OnMouseDown(MouseEventArgs mea)
if (mea.Button == MouseButtons.Left)
mouseDown =
// record the current mouse location
protected override void OnMouseMove(MouseEventArgs mea)
ptMouse =
new Point(mea.X, mea.Y);
// flag the mouse as up and stop adding ripples to the list
protected override void OnMouseUp(MouseEventArgs mea)
if (mea.Button == MouseButtons.Left)
mouseDown =
// add the recorded mouse point to the ripple list
private void AddRipple()
rippleList[ripplePntr] =
new RippleObj(ptMouse);
if (ripplePntr >= rippleList.Length)
ripplePntr = 0;
// draw the ripples
protected override void OnPaint(PaintEventArgs pea)
Color clr;
float w;
Graphics g = pea.Graphics;
g.SmoothingMode = SmoothingMode.HighQuality;
// paint the caption
float cx = g.VisibleClipBounds.Size.Width;
float cy = g.VisibleClipBounds.Size.Height;
SizeF sizef = g.MeasureString(Text, font1);
Brush brush1 =
new SolidBrush(Color.DarkRed);
g.DrawString(Text, font1, brush1,(cx - sizef.Width) / 2,(cy - sizef.Height) / 2);
// loop through the ripple list
for (int i = 0; i < rippleList.Length; i++)
if ((rippleList[i] != null) && (rippleList[i].loc != Point.Empty))
// set the transparency and line width according to the radius size
clr = Color.FromArgb(255-rippleList[i].rad,255,255,255);
w = 0.03f * rippleList[i].rad;
// draw the ellipse
g.DrawEllipse(new Pen(clr, w),rippleList[i].loc.X - rippleList[i].rad,rippleList[i].loc.Y - rippleList[i].rad/4,rippleList[i].rad * 2,rippleList[i].rad/2);
// expand the radius
rippleList[i].rad += 10;
// see if the ripple is too big
if (rippleList[i].rad > 255)
// automatically called by the timer according to the interval set
private void Timer1OnTick(object obj, EventArgs ea)
// check to see if the user has the button pressed and add a ripple to the list if they do
if (mouseDown)
// invalidate the graphics object so it will repaint
// this class defines the make-up of a ripple object
class RippleObj
public Point loc = Point.Empty; // the location of the ripple
public int rad = 0; // the size of it's radius
public RippleObj()
public RippleObj(Point mLoc)
loc = mLoc;
public void Reset()
loc = Point.Empty;
rad = 0;