This interactive application provides a visual demonstration of arcs drawn with various starting and sweep angles using GDI (Graphics Device Interface) graphics.
It aims to help users gain a deeper understanding of how angles affect the rendering of arcs in graphical applications.
- Interactive Visualization: Adjust starting and sweep angles dynamically to see real-time changes in arc rendering.
- Intuitive Controls: User-friendly interface for manipulating angles.
- Educational Tool: Designed to help users grasp the concepts of angles in graphics programming.
Imports System.Drawing.Drawing2D
- This line imports the
System.Drawing.Drawing2D
namespace, which provides advanced 2D graphics functionality. It includes classes for drawing shapes, such as arcs and curves.
Public Class Form1
- This line defines a new class called
Form1
. A class is a blueprint for creating objects. Here,Form1
is a form (window) in the application.
Private Context As BufferedGraphicsContext
Private Buffer As BufferedGraphics
Context
: This variable will hold the graphics context for buffered graphics, which helps in rendering graphics smoothly.Buffer
: This variable is used to store the graphics buffer, which allows for double buffering to reduce flickering during drawing.
Private Structure DisplayStructure
Public Location As Point
Public Text As String
Public Font As Font
End Structure
- This defines a structure called
DisplayStructure
that holds information about where to display text (Location
), the text itself (Text
), and the font used (Font
).
Private CodeDisplay As DisplayStructure
Private CircleOfProgress As Rectangle
Private CircleOfProgressPen As Pen
Private CircleOfProgressBackgroundPen As Pen
CodeDisplay
: An instance ofDisplayStructure
to display code-related information.CircleOfProgress
: A rectangle that defines the area where the arc will be drawn.CircleOfProgressPen
andCircleOfProgressBackgroundPen
: Pens used to draw the arc and its background.
Private startAngle As Single = 0.0F
Private sweepAngle As Single
startAngle
: A variable representing the starting angle for the arc (0 degrees).sweepAngle
: A variable that will hold the sweep angle, which determines how far the arc extends.
Private ReadOnly AlineCenterMiddle As New StringFormat With {
.Alignment = StringAlignment.Center,
.LineAlignment = StringAlignment.Center}
- This creates a
StringFormat
object that centers text both horizontally and vertically.
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
InitializeApp()
Debug.Print($"Program running... {Now.ToShortTimeString}")
End Sub
- This method is called when the form loads. It initializes the application by calling
InitializeApp()
. - It also prints a message to the debug console indicating that the program is running, along with the current time.
Private Sub Form1_Resize(sender As Object, e As EventArgs) Handles Me.Resize
If Not WindowState = FormWindowState.Minimized Then
ResizeCodeDisplay()
ResizeControls()
ResizeCircleOfProgress()
DisposeBuffer()
End If
End Sub
- This method handles the form's resize event. If the window is not minimized, it resizes various components of the form (like text display and controls) and disposes of the buffer to prepare for redrawing.
Private Sub Timer1_Tick(sender As Object, e As EventArgs) Handles Timer1.Tick
If Not WindowState = FormWindowState.Minimized Then
UpdateCodeDisplay()
Invalidate() ' Calls OnPaint Sub
End If
End Sub
- This method is called every time the timer ticks (every 30 milliseconds, as set later). It updates the code display and triggers a repaint of the form.
Protected Overrides Sub OnPaint(ByVal e As PaintEventArgs)
AllocateBuffer(e)
DrawDisplays()
Buffer.Render(e.Graphics)
MyBase.OnPaint(e)
End Sub
- This method is overridden to perform custom painting. It allocates a graphics buffer, draws the displays, and then renders the buffer onto the form.
Private Sub StartAngleTrackBar_Scroll(sender As Object, e As EventArgs) Handles StartAngleTrackBar.Scroll
StartAngleLabel.Text = $"Start Angle: {StartAngleTrackBar.Value}°"
End Sub
Private Sub SweepAngleTrackBar_Scroll(sender As Object, e As EventArgs) Handles SweepAngleTrackBar.Scroll
SweepAngleLabel.Text = $"Sweep Angle: {SweepAngleTrackBar.Value}°"
End Sub
- These methods handle the scrolling of two trackbars (sliders) for adjusting the start angle and sweep angle. They update the corresponding labels to show the current angle values.
Private Sub UpdateCodeDisplay()
CodeDisplay.Text = $"Graphics.DrawArc(Pen, Rectangle, {StartAngleTrackBar.Value}, {SweepAngleTrackBar.Value})"
End Sub
- This method updates the text displayed in the
CodeDisplay
structure to show the current code that would be used to draw the arc with the selected angles.
Protected Overrides Sub OnPaintBackground(ByVal e As PaintEventArgs)
'Intentionally left blank. Do not remove.
End Sub
- This method is overridden but intentionally left blank to prevent flickering during painting.
Private Sub AllocateBuffer(e As PaintEventArgs)
If Buffer Is Nothing Then
Buffer = Context.Allocate(e.Graphics, ClientRectangle)
With Buffer.Graphics
.CompositingMode = Drawing2D.CompositingMode.SourceOver
.TextRenderingHint = Drawing.Text.TextRenderingHint.AntiAlias
.SmoothingMode = Drawing2D.SmoothingMode.HighQuality
.PixelOffsetMode = Drawing2D.PixelOffsetMode.HighQuality
.CompositingQuality = Drawing2D.CompositingQuality.HighQuality
.InterpolationMode = InterpolationMode.HighQualityBicubic
.TextContrast = SmoothingMode.HighQuality
End With
End If
End Sub
- This method checks if the buffer has been allocated. If not, it allocates a new buffer and sets various rendering properties to ensure high-quality graphics.
Private Sub DrawDisplays()
If Buffer IsNot Nothing Then
Try
With Buffer.Graphics
.Clear(SystemColors.Control)
.DrawEllipse(CircleOfProgressBackgroundPen,
CircleOfProgress)
.DrawArc(CircleOfProgressPen,
CircleOfProgress,
StartAngleTrackBar.Value,
SweepAngleTrackBar.Value)
.DrawString(CodeDisplay.Text,
CodeDisplay.Font,
New SolidBrush(SystemColors.ControlText),
CodeDisplay.Location,
AlineCenterMiddle)
End With
Catch ex As Exception
Debug.Print("Draw error: " & ex.Message)
End Try
Else
Debug.Print("Buffer is not initialized.")
End If
End Sub
- This method draws the background ellipse, the arc based on the current angles, and the code display text on the buffer. It also handles any potential drawing errors.
Private Sub DisposeBuffer()
If Buffer IsNot Nothing Then
Buffer.Dispose()
Buffer = Nothing ' Set to Nothing to avoid using a disposed object
End If
End Sub
- This method disposes of the buffer if it exists and sets it to
Nothing
to avoid using a disposed object.
Private Sub InitializeApp()
InitializeForm()
InitializeBuffer()
InitializeLabels()
InitializeTimer()
End Sub
- This method initializes the application by calling several initialization methods for the form, buffer, labels, and timer.
Private Sub InitializeForm()
CenterToScreen()
SetStyle(ControlStyles.OptimizedDoubleBuffer Or ControlStyles.AllPaintingInWmPaint, True)
SetStyle(ControlStyles.UserPaint, True)
Text = "Draw Arc - Code with Joe"
Me.WindowState = FormWindowState.Maximized
End Sub
- This method centers the form on the screen, sets styles for double buffering (to reduce flickering), sets the window title, and maximizes the window.
Private Sub InitializeBuffer()
Context = BufferedGraphicsManager.Current
Context.MaximumBuffer = Screen.PrimaryScreen.WorkingArea.Size
Buffer = Context.Allocate(CreateGraphics(), ClientRectangle)
With Buffer.Graphics
.CompositingMode = Drawing2D.CompositingMode.SourceOver
.TextRenderingHint = Drawing.Text.TextRenderingHint.AntiAlias
.SmoothingMode = Drawing2D.SmoothingMode.HighQuality
.PixelOffsetMode = Drawing2D.PixelOffsetMode.None
.CompositingQuality = Drawing2D.CompositingQuality.HighQuality
End With
End Sub
- This method initializes the graphics buffer context, sets the maximum buffer size, and allocates the buffer with high-quality rendering settings.
Private Sub InitializeTimer()
Timer1.Interval = 30
Timer1.Enabled = True
End Sub
- This method sets the timer interval to 30 milliseconds and enables the timer, which will trigger periodic updates.
Private Sub InitializeLabels()
StartAngleLabel.Text = $"Start Angle: {StartAngleTrackBar.Value}°"
SweepAngleLabel.Text = $"Sweep Angle: {SweepAngleTrackBar.Value}°"
End Sub
- This method initializes the text for the angle labels based on the initial values of the trackbars.
- ResizeCodeDisplay, ResizeControls, ResizeCircleOfProgress
Private Sub ResizeCodeDisplay()
Dim FontSize As Single
If ClientSize.Height / 25 > 13 Then
FontSize = ClientSize.Height / 25
Else
FontSize = 13
End If
Dim YPosition As Integer
If ClientSize.Height / 2.5 > 175 Then
YPosition = ClientSize.Height / 2.5
Else
YPosition = 175
End If
CodeDisplay.Font = New Font("Segoe UI",
FontSize,
FontStyle.Regular)
CodeDisplay.Location.X = ClientSize.Width / 2
CodeDisplay.Location.Y = ClientSize.Height / 2 - YPosition
End Sub
Private Sub ResizeControls()
Dim TrackBarWidth As Integer
If ClientSize.Height / 2 > 225 Then
TrackBarWidth = ClientSize.Height / 2
Else
TrackBarWidth = 225
End If
StartAngleTrackBar.Width = TrackBarWidth
StartAngleTrackBar.Left = ClientSize.Width / 2 - StartAngleTrackBar.Width / 2
StartAngleTrackBar.Top = ClientSize.Height / 2 - StartAngleTrackBar.Height
StartAngleLabel.Left = StartAngleTrackBar.Left + 8
StartAngleLabel.Top = StartAngleTrackBar.Top + 40
SweepAngleTrackBar.Width = TrackBarWidth
SweepAngleTrackBar.Left = ClientSize.Width / 2 - SweepAngleTrackBar.Width / 2
SweepAngleTrackBar.Top = ClientSize.Height / 2 + SweepAngleTrackBar.Height * 0.1
SweepAngleLabel.Left = SweepAngleTrackBar.Left + 8
SweepAngleLabel.Top = SweepAngleTrackBar.Top + 40
End Sub
Private Sub ResizeCircleOfProgress()
Dim PenSize As Single
If ClientSize.Height / 30 > 15 Then
PenSize = ClientSize.Height / 30
Else
PenSize = 15
End If
CircleOfProgressBackgroundPen = New Pen(SystemColors.ControlLightLight,
PenSize)
If ClientSize.Height / 40 > 10 Then
PenSize = ClientSize.Height / 40
Else
PenSize = 10
End If
CircleOfProgressPen = New Pen(SystemColors.MenuHighlight, PenSize) With {
.EndCap = LineCap.Round,
.StartCap = LineCap.Round
}
Dim CircleSize As Single
If ClientSize.Height / 1.5 > 300 Then
CircleSize = ClientSize.Height / 1.5
Else
CircleSize = 300
End If
CircleOfProgress.Width = CircleSize
CircleOfProgress.Height = CircleSize
CircleOfProgress.X = ClientSize.Width / 2 - CircleOfProgress.Width / 2
CircleOfProgress.Y = ClientSize.Height / 2 - CircleOfProgress.Height / 2
End Sub
- These methods adjust the size and position of the code display, controls (like trackbars), and the drawing area (circle) based on the current size of the form.
This code creates an interactive application that allows users to visualize how arcs are drawn based on different starting and sweep angles. It uses VB.NET's GDI+ for graphics rendering and provides a user-friendly interface for manipulating the angles. Each section of the code is designed to handle specific aspects of the application, from initialization to drawing and resizing components.