Graphics & GDI+ Drawing
Master VB 2026's drawing engine — the Graphics object, Pen and Brush, lines, rectangles, ellipses, text, polygons, pie charts, gradients, and animated graphics with the Timer control.
Paint event through a Graphics object. The coordinate origin (0, 0) is the top-left corner; X increases right, Y increases down. Always wrap Pen and Brush objects in Using blocks so they are disposed immediately after use. Call picBox.Invalidate() to trigger a repaint — never store the Graphics object; get a fresh one from the Paint event each time.
26.1 The Graphics Object & Paint Event
GDI+ drawing always happens in response to the Paint event. The event argument e.Graphics provides the drawing surface. Every time the window is resized, uncovered, or Invalidate() is called, the Paint event fires and you redraw from scratch.
' --- Drawing on a PictureBox --- Private Sub picBox_Paint(sender As Object, e As PaintEventArgs) Handles picBox.Paint Dim g As Graphics = e.Graphics g.SmoothingMode = Drawing2D.SmoothingMode.AntiAlias ' smooth curves ' Draw a red line Using pen As New Pen(Color.Red, 2) g.DrawLine(pen, 10, 10, 200, 10) End Using ' Fill a blue rectangle Using brush As New SolidBrush(Color.SteelBlue) g.FillRectangle(brush, 10, 30, 120, 60) End Using ' Draw a green circle (ellipse in square bounding box) Using pen As New Pen(Color.Green, 3) g.DrawEllipse(pen, 150, 30, 60, 60) End Using End Sub ' --- Drawing on the Form itself --- Private Sub Form1_Paint(...) Handles MyBase.Paint Dim g = e.Graphics ' draws directly on the form surface End Sub ' --- Trigger a repaint (e.g. from a button click) --- Private Sub btnDraw_Click(...) Handles btnDraw.Click picBox.Invalidate() ' schedules Paint; does NOT draw immediately End Sub ' --- WRONG — never store the Graphics object --- ' Dim g As Graphics = picBox.CreateGraphics() ← erased on repaint! ' Use Invalidate() + Paint event instead. ' --- Clear the canvas --- g.Clear(Color.White) ' fill entire surface with White
The origin (0, 0) is the top-left corner. X increases to the right; Y increases downward. A rectangle at (10, 30, 120, 60) means: left=10, top=30, width=120, height=60 — so its right edge is at X=130 and bottom edge at Y=90.
26.2 Lines and Rectangles
Private Sub picBox_Paint(...) Handles picBox.Paint Dim g = e.Graphics g.SmoothingMode = Drawing2D.SmoothingMode.AntiAlias ' --- Lines --- Using pen As New Pen(Color.Black, 1) g.DrawLine(pen, 10, 10, 200, 10) ' horizontal g.DrawLine(pen, 10, 10, 10, 100) ' vertical g.DrawLine(pen, 10, 10, 200, 100) ' diagonal End Using ' Dashed line using DashStyle Using dashPen As New Pen(Color.Gray, 1) dashPen.DashStyle = Drawing2D.DashStyle.Dash g.DrawLine(dashPen, 10, 120, 200, 120) End Using ' --- Rectangles --- Using pen As New Pen(Color.Navy, 2) g.DrawRectangle(pen, 20, 20, 100, 60) ' outline only End Using Using brush As New SolidBrush(Color.LightBlue) g.FillRectangle(brush, 140, 20, 100, 60) ' filled End Using ' Fill + outline Using brush As New SolidBrush(Color.Coral) g.FillRectangle(brush, 20, 100, 80, 40) End Using Using pen As New Pen(Color.DarkRed, 2) g.DrawRectangle(pen, 20, 100, 80, 40) ' draw outline on top End Using ' Rounded rectangle (using GraphicsPath) Using path As New Drawing2D.GraphicsPath() Dim r = 12 ' corner radius path.AddArc(120, 100, r, r, 180, 90) path.AddArc(120 + 80 - r, 100, r, r, 270, 90) path.AddArc(120 + 80 - r, 100 + 40 - r, r, r, 0, 90) path.AddArc(120, 100 + 40 - r, r, r, 90, 90) path.CloseFigure() Using brush As New SolidBrush(Color.MediumPurple) g.FillPath(brush, path) End Using End Using End Sub
Configure a shape and click Draw. The canvas shows the result and the code panel shows the exact VB DrawLine / DrawRectangle / FillRectangle call that produced it.
26.3 Ellipses, Circles, and Arcs
Ellipses and circles are drawn using a bounding rectangle — the ellipse fits exactly inside that rectangle. A circle is simply an ellipse whose bounding rectangle is a square. DrawArc draws a portion of the ellipse between a start angle and sweep angle (both in degrees, measured clockwise from 3 o'clock).
' Ellipse: fits inside bounding rect (x, y, width, height) g.DrawEllipse(New Pen(Color.Blue, 2), 10, 10, 150, 80) ' outline g.FillEllipse(New SolidBrush(Color.SkyBlue), 10, 10, 150, 80) ' filled ' Circle: width = height g.FillEllipse(New SolidBrush(Color.Gold), 50, 50, 80, 80) ' filled circle r=40 ' Arc: part of an ellipse ' startAngle: 0=right, 90=bottom, 180=left, 270=top (clockwise) ' sweepAngle: degrees to sweep clockwise from startAngle Using pen As New Pen(Color.Red, 3) g.DrawArc(pen, 10, 110, 100, 100, 0, 270) ' ¾ of a circle End Using ' Concentric circles (target / radar effect) For r = 10 To 80 Step 20 Dim cx = 120 : Dim cy = 100 Using pen As New Pen(Color.FromArgb(255 - r * 2, 0, 120, 200), 2) g.DrawEllipse(pen, cx - r, cy - r, r * 2, r * 2) End Using Next ' Progress ring (arc showing percentage) Dim pct = 75 Dim sweep = 360 * pct \ 100 g.DrawArc(New Pen(Color.LimeGreen, 8), 20, 20, 80, 80, -90, sweep) ' -90 starts at top
Draw circles, ellipses, arcs, and concentric rings. Adjust the start angle and sweep to understand the arc coordinate system, then build a progress ring.
26.4 Drawing Text with DrawString
DrawString renders text on any drawing surface. You need a Font object (name, size, style) and a Brush for color. Use MeasureString to calculate text dimensions for centering or wrapping.
' --- Basic text --- Using font As New Font("Segoe UI", 14, FontStyle.Regular) Using brush As New SolidBrush(Color.Black) g.DrawString("Hello, VB 2026!", font, brush, 10, 10) End Using : End Using ' --- Bold, Italic, Underline --- Using boldFont As New Font("Arial", 12, FontStyle.Bold) Using italFont As New Font("Arial", 12, FontStyle.Italic) Using underFont As New Font("Arial", 12, FontStyle.Underline) Using brush As New SolidBrush(Color.DarkBlue) g.DrawString("Bold", boldFont, brush, 10, 50) g.DrawString("Italic", italFont, brush, 10, 75) g.DrawString("Underline", underFont, brush, 10, 100) End Using : End Using : End Using : End Using ' --- Centred text using MeasureString --- Dim text = "Centred Title" Using font As New Font("Segoe UI", 16, FontStyle.Bold) Using brush As New SolidBrush(Color.Navy) Dim sz = g.MeasureString(text, font) Dim x = (picBox.Width - sz.Width) / 2 Dim y = (picBox.Height - sz.Height) / 2 g.DrawString(text, font, brush, x, y) End Using : End Using ' --- Text inside a rectangle with StringFormat --- Dim rect As New Rectangle(10, 10, 200, 60) Dim fmt As New StringFormat() fmt.Alignment = StringAlignment.Center ' horizontal fmt.LineAlignment = StringAlignment.Center ' vertical Using font As New Font("Segoe UI", 12) Using brush As New SolidBrush(Color.White) g.FillRectangle(New SolidBrush(Color.SteelBlue), rect) g.DrawString("Vertically & Horizontally Centred", font, brush, rect, fmt) End Using : End Using
Type text, choose font settings, and see how DrawString renders it — including automatic centring via MeasureString.
26.5 Polygons and Pie Charts
Polygons take an array of Point structures. VB automatically closes the shape by connecting the last point back to the first. Pie slices use DrawPie/FillPie with the same bounding rectangle as an ellipse, plus start and sweep angles.
' --- Triangle --- Dim tri() = { New Point(100, 10), New Point(180, 130), New Point(20, 130) } g.FillPolygon(New SolidBrush(Color.LightGreen), tri) g.DrawPolygon(New Pen(Color.DarkGreen, 2), tri) ' --- Regular hexagon (calculated with trig) --- Dim cx = 150, cy = 100, radius = 60 Dim hex(5) As Point For i = 0 To 5 Dim angle = Math.PI * (2 * i - 1) / 6 ' 60° steps, flat-top orientation hex(i) = New Point(cx + CInt(radius * Math.Cos(angle)), cy + CInt(radius * Math.Sin(angle))) Next g.FillPolygon(New SolidBrush(Color.SteelBlue), hex) ' --- Pie chart slices --- ' bounding rect: x=10, y=10, width=200, height=200 ' Angles: 0° = 3-o'clock, clockwise. Use -90 to start at 12. g.FillPie(New SolidBrush(Color.Red), 10, 10, 200, 200, -90, 108) ' 30% g.FillPie(New SolidBrush(Color.Blue), 10, 10, 200, 200, 18, 144) ' 40% g.FillPie(New SolidBrush(Color.Green), 10, 10, 200, 200, 162, 72) ' 20% g.FillPie(New SolidBrush(Color.Orange), 10, 10, 200, 200, 234, 36) ' 10% ' Exploded slice (offset one slice from the centre) Dim explodeDist = 12 Dim midAngle = Math.PI * (-90 + 108 / 2) / 180 ' midpoint of first slice Dim offX = CInt(explodeDist * Math.Cos(midAngle)) Dim offY = CInt(explodeDist * Math.Sin(midAngle)) g.FillPie(New SolidBrush(Color.Red), 10 + offX, 10 + offY, 200, 200, -90, 108)
Enter up to 5 data values with labels. The chart auto-calculates sweep angles, draws each FillPie slice, and shows the exact VB code — including the running start angle.
26.6 Gradient Fills and Color
The LinearGradientBrush smoothly transitions between two colours along a line. PathGradientBrush radiates a gradient from a centre point. Use Color.FromArgb(alpha, r, g, b) to set transparency (alpha 0 = fully transparent, 255 = fully opaque).
Imports System.Drawing.Drawing2D ' --- Horizontal gradient --- Using lgb As New LinearGradientBrush( New Point(0, 0), New Point(200, 0), Color.DodgerBlue, Color.MediumPurple) g.FillRectangle(lgb, 10, 10, 200, 50) End Using ' --- Vertical gradient --- Using lgb As New LinearGradientBrush( New Point(0, 0), New Point(0, 80), Color.Orange, Color.OrangeRed) g.FillRectangle(lgb, 10, 80, 200, 80) End Using ' --- Diagonal gradient --- Using lgb As New LinearGradientBrush( New Point(230, 0), New Point(430, 170), Color.LimeGreen, Color.Navy) g.FillEllipse(lgb, 230, 10, 180, 160) End Using ' --- Transparent overlay --- Using brush As New SolidBrush(Color.FromArgb(120, Color.Red)) g.FillEllipse(brush, 60, 20, 100, 100) ' 47% opaque End Using ' --- PathGradientBrush: radial from centre --- Dim pts() = {New Point(150,10), New Point(250,80), New Point(200,160), New Point(100,160), New Point(50,80)} Using pgb As New PathGradientBrush(pts) pgb.CenterColor = Color.White pgb.SurroundColors = {Color.DodgerBlue} g.FillPolygon(pgb, pts) End Using
A complete drawing scene combining gradients, polygons, ellipses, text, and transparency — all in a single Paint event. Use the preset buttons to switch scenes, then inspect the full VB code.
26.7 GitHub Copilot — Animated Clock
' Draw an analog clock using GDI+ — Timer fires every 1 s, rotate hour/minute/second hands with trigonometry, draw hour marks, shade the face with a radial gradient.'' Analog clock — runs on Timer1.Interval = 1000. Private Sub picClock_Paint(...) Handles picClock.Paint Dim g = e.Graphics g.SmoothingMode = Drawing2D.SmoothingMode.AntiAlias Dim cx = picClock.Width \ 2 Dim cy = picClock.Height \ 2 Dim r = Math.Min(cx, cy) - 10 ' Radial gradient face Dim pts() = {New Point(cx, cy)} Using pgb As New Drawing2D.PathGradientBrush(pts) pgb.CenterPoint = New PointF(cx, cy) pgb.CenterColor = Color.White pgb.SurroundColors = {Color.LightSteelBlue} pgb.FocusScales = New PointF(0, 0) g.FillEllipse(pgb, cx - r, cy - r, r * 2, r * 2) End Using g.DrawEllipse(New Pen(Color.Navy, 3), cx - r, cy - r, r * 2, r * 2) ' Hour marks For i = 0 To 11 Dim a = Math.PI * (2 * i) / 12 - Math.PI / 2 Dim x1 = cx + CInt((r - 8) * Math.Cos(a)) Dim y1 = cy + CInt((r - 8) * Math.Sin(a)) Dim x2 = cx + CInt((r - 20) * Math.Cos(a)) Dim y2 = cy + CInt((r - 20) * Math.Sin(a)) g.DrawLine(New Pen(Color.Navy, 2), x1, y1, x2, y2) Next ' Hands Dim now = DateTime.Now DrawHand(g, cx, cy, r * 0.5, Math.PI * (2 * now.Hour + now.Minute / 60) / 12 - Math.PI / 2, Color.Navy, 5) DrawHand(g, cx, cy, r * 0.75, Math.PI * (2 * now.Minute + now.Second / 60) / 60 - Math.PI / 2, Color.DarkBlue, 3) DrawHand(g, cx, cy, r * 0.85, Math.PI * 2 * now.Second / 60 - Math.PI / 2, Color.Red, 1) End Sub Private Sub DrawHand(g As Graphics, cx%, cy%, length#, angle#, c As Color, thick%) Dim x = cx + CInt(length * Math.Cos(angle)) Dim y = cy + CInt(length * Math.Sin(angle)) g.DrawLine(New Pen(c, thick), cx, cy, x, y) End Sub Private Sub Timer1_Tick(...) Handles Timer1.Tick picClock.Invalidate() ' redraw every second End Sub
Try these in the Copilot Chat panel:
- "Draw a bar chart from a Dictionary(Of String, Integer) where keys are month names and values are sales figures — auto-scale bars to fit the PictureBox height"
- "Create a Spirograph — use two nested For loops with Math.Sin/Cos to draw a parametric curve with configurable R, r, and d constants"
- "Draw a star polygon with n points using FillPolygon — calculate the outer and inner radius points alternating to create the star shape"
- "Add a rubber-band selection rectangle: track MouseDown, MouseMove, MouseUp coordinates and draw a dashed rectangle updated in real time"
Lesson Summary
- All GDI+ drawing happens inside the Paint event. Get the drawing surface from
e.Graphics. Callcontrol.Invalidate()to request a repaint — never store the Graphics object between events. - Origin (0, 0) is top-left. X increases right; Y increases downward. Shapes use (x, y, width, height) bounding rectangle coordinates.
- Always wrap
Pen,Brush, andFontinUsingblocks — they hold GDI+ handles that must be released immediately after drawing. DrawLine / DrawRectangle / DrawEllipse / DrawPolygondraw outlines (need aPen).Fillvariants fill the interior (need aBrush). You can layer both.- Set
g.SmoothingMode = AntiAliasfor smooth curves. Arcs measure angles in degrees, clockwise from 3 o'clock (use −90° to start at 12 o'clock). DrawStringrenders text with aFont+Brush. UseMeasureStringto compute text dimensions for precise centring.StringFormatcontrols horizontal and vertical alignment inside a rectangle.LinearGradientBrushfills shapes with smooth colour transitions.Color.FromArgb(alpha, R, G, B)controls transparency (0–255).- Combine GDI+ with Timer: set
Timer.Interval, callInvalidate()in the Tick handler, and useDateTime.Now+ trigonometry for animated clocks, progress bars, and simulations.
Exercises
Exercise 26.1 — Bar Chart Generator
- Accept 5 data values in TextBoxes. Compute the maximum and scale each bar to fill the PictureBox height proportionally.
- Draw each bar as a gradient-filled rectangle (
LinearGradientBrush) with a contrasting outline. - Label the value above each bar and the category name below using
DrawString+MeasureStringto centre both. - Add a horizontal grid line at 25%, 50%, 75%, 100% using a dashed
Pen. - Copilot challenge: "Auto-resize the chart when the PictureBox is resized — calculate bar width and height dynamically from picBox.Width and picBox.Height"
Exercise 26.2 — Analog Clock
- Build a PictureBox-based analog clock using the Copilot example as a starting point.
- Add minute marks (60 shorter lines between the 12 hour marks).
- Show the current time as a digital readout below the clock face using
DrawString. - Add a start/stop button that enables/disables
Timer1. - Copilot challenge: "Draw a dropshadow under the clock face using a semi-transparent SolidBrush offset by 4px right and 4px down"
Exercise 26.3 — Pie Chart with Legend
- Define 5 named data values (budget categories). Calculate each slice's sweep angle as
value / total * 360. - Draw each slice with
FillPieusing a preset color palette, then outline withDrawPie. - Explode the largest slice by offsetting it along the radius midpoint.
- Draw a legend: coloured square + label + percentage, stacked vertically to the right of the pie.
- Copilot challenge: "Add mouse-click detection: on MouseDown, compute which slice was clicked using the angle from the centre point, and highlight that slice"
Related Resources
← Lesson 25
OOP — Classes and Inheritance.
Lesson 27 →
Timer — animation and countdown.
MS Docs — GDI+
Complete GDI+ graphics reference for WinForms.
Graphics Class API
All Graphics methods including Draw and Fill variants.
Featured Books
Visual Basic 2022 Made Easy
GDI+ graphics chapters with complete chart and animation examples.
View on Amazon →
VB Programming With Code Examples
Worked programs including drawing applications, clocks, and animated graphics.
View on Amazon →