- Table of Contents
- .NET Book Recommendations
- What Is .NET?
- The Microsoft .NET Framework
- The Common Language Runtime (CLR), the Common Type System (CTS), and the Common Language Specification (CLS)
- .NET Framework Class Library
- Visual Studio .NET
- .NET Enterprise Servers and .NET My Services
- .NET Compliant Languages
- C#
- Visual Basic .NET (VB .NET)
- ASP.NET
- XML Web Services
- ADO.NET
- XML.NET
- Windows Forms
- Why .NET?
- Displaying Errors with the Error Provider
- COM Interoperability
- Comparing Java and .NET
- Calling Unmanaged Code
- .NET Application Security
- Code Access Security
- .NET Standards Support
- Numeric Types in the .NET Framework
- Working with Strings
- Formatting Strings
- Trimming Character Strings
- Comparing Strings in .NET 2.0
- Arrays and Collections
- Arrays as Class Members
- Sorting a Multi-Dimensional Array
- Sorting a Multi-Dimensional Array with LINQ
- File I/O (System.IO)
- Working with File Names
- Using the File System
- Working with Files and Directories
- Monitoring the File System
- Working with Streams
- Working with Text Encodings
- Working with Date and Time
- Extending the DateTime Class
- Fun with Dates
- Exceptions
- Delegates
- Events
- Asynchronous Programming
- Asynchronous File I/O
- Timers
- Random Numbers
- Cryptographically Secure Random Numbers
- Serialization
- MultiThreading (System.Threading)
- Multi-Threading Overview
- The Managed Thread Pool
- Managed Threading
- Thread Synchronization
- Synchronizing Data Access
- Trace Debugging
- Tracing in .NET 2.0
- ASP.NET Trace
- Validating User Input in ASP.NET Web Pages
- Event Logging
- Monitoring Application Performance
- Accessing the Registry
- Accessing Environment Information
- Environment Variables in .NET 2.0
- Managing Windows Forms Applications
- Working with Email
- Working with Graphics
- Animating a Background
- Working with Images
- Drawing Cycloid Curves
- Simulating the Spirograph
- Building International Web Applications
- .NET Compact Framework
- Mobile Web Development with ASP.NET
- Speech Technologies
- Microsoft MapPoint Web Service
- Working with Typed DataSets
- Using Relationships in DataSets
- DataColumn Expressions
- Playing Simple Sounds
- Playing Sounds with .NET 2.0
- Returning an Image in a Web Page
- RSS
- Best Practices Project Structure
- Best Practices Application Blocks
- The Data Access Application Block
- The Exception Management Application Block
- Best Practices — Performance
- Best Practices — Performance and Scalability
- Best Practices - Testing
- Reading the Tea Leaves, 2005
- Predictions: A Look Back at 2005, and a Look Ahead to 2006
- .NET Downloads
- Application Deployment Overview
- Application Deployment — Versioning
- Application Deployment — Version Policy
- Application Deployment — Packaging and Distribution
- .NET Remoting Overview
- A Remoting Demonstration
- Remoting Configuration
- Remoting: Lifetimes and Leases
- Remoting: Other Issues
- Attributes
- Writing Custom Attributes
- Accessing Attributes in Code
- Reflection
- Class Design: Inheritance, Interface, or Composition?
- The TriTryst Game
- Console Applications in .NET 2.0
- New File I/O Methods in .NET 2.0
- Building Projects with MSBuild
- Unmanaged Callbacks in .NET 2.0
- Timer Troubles
- Non-Rectangular Windows Forms
- Windows Forms Transparency
- 10 Things I Hate About Visual Basic
- 10 Things I Hate About C#
- Background Processing with Idle Time
- Scaling Windows Forms
- Reading and Writing Binary Data
- New Memory Management Functions in .NET 2.0
- Compatibility Between .NET 1.1 and .NET 2.0
- Managed Debugging Assistants in .NET 2.0
- XDir: A Program for Viewing Directory Sizes
- The Microsoft.VisualBasic Namespace
- Operator Overloading
- Working with GPS Data
- Hidden Visual Studio Tools
- .NET 3.0
- The .NET 2.0 Stopwatch Class
- Nullable Types
- Drawing Rotated Text
- Unsafe Code
- Other .NET Languages
- Compiler Directives
- Safe Handles
- Predictions, 2007 Edition
- New Features in C# 3.0
- Generics
- Network Client Programming
- On the Misuse of Exceptions
- Maximum Object Size in .NET
- More on Maximum Object Sizes
- Keyed Collection Memory Limitations
- Matching String Endings
- Allocating Small Data Structures
- Grumbling About Limitations
- Some Thoughts on the Nature of What We Do
- Working with Predicates in Collections
- Working with DataReaders
- Outputting XML with XmlWriter
- Writing XML Data
- Working with Compression
- Another Look at Compressed Streams
- Compressing a Very Large File
- Canonical URIs
- Constructing URIs
- Using OneWayAttribute for Remote Calls
- Selecting a Garbage Collector
- Linked List
- Linked List Application - The MRU List
- Auto-implemented Properties in C#
- The HashSet Collection
- Looking Ahead: 2018
- An Experiment in Optimization
- A Larger Integer
- Extension Methods
- Language Integrated Query (LINQ)
- Variable Length Parameter Lists
- The ReaderWriterLockSlim Synchronization Primitive
- Sorting a Text File
- Sorting a Large Text File
- Using ListView with Large Data Sets
- LINQ One-Liners
- Regular Expression Optimization
- Random File I/O
- Computing the Size of a Structure
- More on Computing Structure Sizes
- UnmanagedMemoryStream
- Dynamically Loading Code
- Building a String Table
- Delegates Versus Function Pointers
- Visual Studio Editor Features
- A Simple Profile Timer
- New Features in C# 4.0
- IEnumerator or IList?
- New Features in .NET 4.0
- Set Operations with IEnumerable and HashSet
- Using File Locks
- Extending Object Functionality
- Clearing a HashSet
- When Hash Codes Matter
- Parsing Command Line Options
- Creating a Single-Instance Program
- Asynchronous Windows Forms Events
- The BackgroundWorker Component
- Fixing a Dumb Mistake
- Thinking About Multi-Threaded Programs
- JavaScript Object Notation
- Useful .NET-related Sites
- Markov Models
- Building an Order 0 Markov Model
- Higher Order Markov Models
- Webmaster's Guide to robots.txt
- An Overview of the Parallel Extensions to .NET
- Parallel Extensions Synchronization Objects
- Thread Safe Collections
- A Bug and a Conundrum
- Another Bug and an Answer
- Task Parallel Library
- Good and Bad Ideas in C#
- Parallel LINQ
- Copying Large Files
- Replacing File.Copy
- Learning from Our Mistakes
- Symbolic Links
- There Is No Easy Fix
- Tracking Hurricanes
- Examining Hurricane Data
- Searching for Multiple Strings
- Simple JSON Processing
- Aho-Corasick String Searching
- Writing a Web Crawler
- Web Crawler Politeness
- Source Control Management
- Subversion
- Communicating with Datagrams
- Fun with Actions and Funcs New
- The Future of Media
- The Importance of Metadata
- Of Comparison and IComparer
- IComparer, Comparer, IComparable, Oh My!
- Comparing Generic Types New
- A Simple HTTP Server New
- Informit Reference Library
Simulating the Spirograph
Last updated Oct 7, 2005.
Simulating the Spirograph toy requires that you learn about a number of different .NET techniques as well as a little bit of math to understand how to draw the curves. A previous article, Drawing Cycloid Curves, covered the math and showed some very simple code that draws Spirograph-like curves. You should read that article if you want to understand more about how these curves work.
The code presented in the previous article works, but it's not very flexible. The biggest problem is that you have to modify the code and recompile if you want to change any of the curve parameters. That doesn't make for a very friendly program. The other problem is that the curve drawing code is embedded in the form code, making it impossible to re-use for other programs. In this article we will create a program with a nicer user interface and move the curve drawing code to its own assembly so that other programs can use it, too.
Creating the User Interface
The Spirograph simulation program (Spiromania) should allow the user to enter all of the curve parameters and the type of curve (epitrochoid or hypotrochiod) to be drawn. A "Go" button draws the curve. Since you can create some interesting images by drawing one curve on top of another, it's useful to have a "Clear" button that will blank the drawing surface rather than having the program clear the canvas before every curve is drawn. The completed user interface is shown below in Figure 56.
Figure 56 - The Spiromania program's user interface
I started by setting the initial window size in the Form Designer to 800 by 600. Then I added two Panel controls to the form. I created the top panel, pnlControl, first and set its Dock property to Top. That will cause the panel to extend horizontally across the entire top of the form. The second panel is called pnlDraw. Its Doc property is set to Fill so that it will fill the entire remainder of the form. I set the BackColor property to White.
Adding the controls to the top panel is very simple work. I followed the suggested naming conventions and named the controls as follows:
|
Control |
Name |
|
Fixed circle radius |
txtRadiusA |
|
Rolling circle radius |
txtRadiusB |
|
Pen distance |
txtPenDistance |
|
Points Per Curve |
txtPointsPerCurve |
|
Outside |
rbOutside |
|
Inside |
rbInside |
|
Go button |
btnGo |
|
Clear button |
btnClear |
With that user interface defined, it's time to create the button event handlers. The Go button handler has to get the curve parameters from the input controls and then set up to call the code that actually draws the curve. The first pass at that code, minus the curve drawing call, looks like this:
[C#]
private void btnGo_Click(object sender, System.EventArgs e)
{
int aRadius;
int bRadius;
int distance;
int PointsPerCurve;
CurveType ct;
// Get the parameters
aRadius = int.Parse(txtRadiusA.Text);
bRadius = int.Parse(txtRadiusB.Text);
distance = int.Parse(txtPenDistance.Text);
PointsPerCurve = int.Parse(txtPointsPerCurve.Text);
if (rbOutside.Checked)
ct = CurveType.Epitrochoid;
else
ct = CurveType.Hypotrochoid;
// set up to draw
using (Graphics g = pnlDraw.CreateGraphics())
{
PointF ptOrigin = new PointF(
pnlDraw.ClientRectangle.Width/2,
pnlDraw.ClientRectangle.Height/2);
// Insert call to draw here
}
}
private void btnClear_Click(object sender, System.EventArgs e)
{
// Clear the drawing panel.
using (Graphics g = pnlDraw.CreateGraphics())
{
g.Clear(pnlDraw.BackColor);
}
}
[Visual Basic]
Private Sub btnGo_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnGo.Click Dim aRadius As Integer Dim bRadius As Integer Dim distance As Integer Dim PointsPerCurve As Integer Dim ct As CurveType ' Get the parameters aRadius = Integer.Parse(txtRadiusA.Text) bRadius = Integer.Parse(txtRadiusB.Text) distance = Integer.Parse(txtPenDistance.Text) PointsPerCurve = Integer.Parse(txtPointsPerCurve.Text) If rbOutside.Checked Then ct = CurveType.Epitrochoid Else ct = CurveType.Hypotrochoid End If ' set up to draw Dim g As Graphics = pnlDraw.CreateGraphics() Try Dim ptOrigin As New PointF( _ pnlDraw.ClientRectangle.Width / 2, _ pnlDraw.ClientRectangle.Height / 2) ' Insert call to draw here Finally g.Dispose() End Try End Sub Private Sub btnClear_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnClear.Click Dim g As Graphics = pnlDraw.CreateGraphics() Try g.Clear(pnlDraw.BackColor) Finally g.Dispose() End Try End Sub
Other than the call to the drawing code, the biggest thing that the code above lacks is validation of the input parameters. There is no code that checks to see if the values input are actually numbers or that they make sense. The program will throw an exception if you input non-numeric data, and negative or zero values for some of the parameters will surely cause trouble. Those problems are easily solved by adding an ErrorProvider to the form and responding to the individual controls' Validating events. We'll leave that modification for another time.



Account Sign In
View your cart