Option Strict On
Option Explicit On
Public Class Form1
Private uxSineWaveControl As SineWaveControl
Private WithEvents uxFreq As TrackBar
Sub New()
InitializeComponent()
Me.Size = New Size(800, 600)
uxSineWaveControl = New SineWaveControl
uxSineWaveControl.Width = 760
uxSineWaveControl.Height = 400
uxSineWaveControl.Location = New Point(20, 20)
uxSineWaveControl.Anchor = AnchorStyles.Bottom Or AnchorStyles.Left Or _
AnchorStyles.Right Or AnchorStyles.Top
Me.Controls.Add(uxSineWaveControl)
uxFreq = New TrackBar
uxFreq.Width = 300
uxFreq.Location = New Point(20, uxSineWaveControl.Bottom + 20)
uxFreq.Minimum = 1
uxFreq.Maximum = 10000 ' we'll divide by 100...
uxFreq.TickFrequency = 500
uxFreq.Anchor = AnchorStyles.Bottom Or AnchorStyles.Left
Me.Controls.Add(uxFreq)
End Sub
Private Sub uxFreq_ValueChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles uxFreq.ValueChanged
uxSineWaveControl.Frequency = CType(uxFreq.Value / 100, Single)
Me.Text = "Frequency: " & uxSineWaveControl.Frequency.ToString
' We need to ask the control to repaint itself.
uxSineWaveControl.Invalidate()
End Sub
End Class
' Custom control reponsible for drawing itself.
Public Class SineWaveControl
Inherits Control
Private m_Freq As Single
' Math.pi is too precise (double), as a tweak we'll make a less precise version (single).
Private Const pi As Single = CSng(Math.PI)
Sub New()
' Double buffer to reduce flicker.
Me.SetStyle(ControlStyles.AllPaintingInWmPaint Or ControlStyles.OptimizedDoubleBuffer Or _
ControlStyles.UserPaint Or ControlStyles.ResizeRedraw, True)
Me.UpdateStyles()
End Sub
Public Property Frequency() As Single
Get
Return m_Freq
End Get
Set(ByVal value As Single)
m_Freq = value
End Set
End Property
' why override? see: [URL unfurl="true"]http://www.bobpowell.net/overrideorhandle.htm[/URL]
Protected Overrides Sub OnPaint(ByVal e As System.Windows.Forms.PaintEventArgs)
' No need to CreateGraphics, we get one in the event args.
' Smoothing, I don't like it for graphs:
' e.Graphics.SmoothingMode = Drawing2D.SmoothingMode.HighQuality
' The clientsize property is the usable size, it does not include borders/titlebars and whatnot
Dim halfHeight As Single = Convert.ToSingle(Me.ClientSize.Height / 2)
e.Graphics.Clear(Color.White)
'The pen will be disposed of immediately after use when it is declared in a function call.
e.Graphics.DrawLine(New Pen(Color.Blue, 2), New PointF(0, halfHeight), New PointF(Me.ClientSize.Width, halfHeight))
Dim points(Me.ClientSize.Width * 2) As PointF
' we'll get it smoother by drawing 2 points as we move 1 pixel across (though this is wasteful when freq is large)
For i As Integer = 0 To Me.ClientSize.Width * 2
' Multiply by halfheight - 1 as the bottom was getting clipped. The rest is the function stripped down a bit.
' And we need to CType as Option Strict is On.
points(i) = New PointF(CType(i / 2, Single), halfHeight + _
CType(Math.Sin(i * m_Freq * pi / Me.ClientSize.Width) * (halfHeight - 1), Single))
Next
e.Graphics.DrawLines(Pens.Red, points)
MyBase.OnPaint(e)
' Don't dispose of e.graphics - windows is in charge of it.
End Sub
End Class