When I use standard GDI graphics methods, like DrawRectangle or
FillEllipse, I've noticed that the results are slightly off.
I seldom work with graphics, but I'm doing a project now which
requires me to draw precise shapes. I've discovered that, in order to
get crisp results, I have to "nudge" the coordinates. For instance,
instead of drawing a rectangle with
DrawRectangle(Pen1, X, Y, Width, Height)
I must use
DrawRectangle(Pen1, X + 0.001953, Y + 0.001953, Width, Height)
Is anyone familiar with this issue? I'm guessing it is a problem with
Windows (I'm using Windows XP Pro), but I'd like to learn more.
-TC
I wasn't very clear in my original post. What I meant to say is that
in pixel mode with no smoothing, I find that the graphics methods are
imprecise. Specifically, they seem to suffer from rounding errors when
Single arguments are used, and they seem to have inconsistent
definitions of "Width" and "Height". The result is shapes that don't
look as expected, and which must be "nudged" to fit properly into
place.
I wrote a simple form which illustrates what I'm talking about. I'd be
grateful if other people would try this form and let me know if the
problems I'm seeing affect only me, only XP systems, or all Windows
systems.
-TC
Imports System.Drawing
Imports System.Windows.Forms
Public Class GraphicsTestForm
Inherits Form
Private FlowLayoutPanel1 As FlowLayoutPanel
Private TextBox1 As TextBox
Private WithEvents ComboBox1 As ComboBox
Private TextBox2 As TextBox
Private WithEvents Panel1 As Panel
Public Sub New()
'TextBox1
TextBox1 = New TextBox
With TextBox1
.BorderStyle = BorderStyle.FixedSingle
.Multiline = True
.ReadOnly = True
.Size = New Size(400, 60)
.TabStop = False
.Text = "This form demonstrates the implementation of graphics
methods by drawing shapes inside a 100x100 white square with a 1-pixel
margin."
End With
'ComboBox1
ComboBox1 = New ComboBox
With ComboBox1
.Width = 400
.Items.AddRange(New String() {"DrawLine", "DrawRectangle 1",
"DrawRectangle 2", "FillRectangle 1", "FillRectangle 2",
"DrawEllipse", "FillEllipse"})
.MaxDropDownItems = 20
End With
'TextBox2
TextBox2 = New TextBox
With TextBox2
.BorderStyle = BorderStyle.FixedSingle
.Multiline = True
.ReadOnly = True
.Size = New Size(400, 60)
.TabStop = False
End With
'Panel1
Panel1 = New Panel
With Panel1
.BackColor = Color.White
.BorderStyle = BorderStyle.FixedSingle
.ClientSize = New Size(100, 100)
End With
'FlowLayoutPanel1
FlowLayoutPanel1 = New FlowLayoutPanel
With FlowLayoutPanel1
.Controls.Add(TextBox1)
.Controls.Add(ComboBox1)
.Controls.Add(TextBox2)
.Controls.Add(Panel1)
.Dock = DockStyle.Fill
.FlowDirection = FlowDirection.TopDown
End With
'Me
With Me
.Controls.Add(FlowLayoutPanel1)
.ClientSize = New Size(420, 300)
End With
End Sub
Private Sub Panel1_Paint(ByVal sender As Object, ByVal e As
System.Windows.Forms.PaintEventArgs) Handles Panel1.Paint
Select Case ComboBox1.Text
Case "DrawLine"
e.Graphics.DrawLine(Pens.Red, 1, 1, 1, 98)
e.Graphics.DrawLine(Pens.Red, 1, 98, 98, 98)
e.Graphics.DrawLine(Pens.Red, 98, 98, 98, 1)
e.Graphics.DrawLine(Pens.Red, 98, 1, 1, 1)
Case "DrawRectangle 1"
e.Graphics.DrawRectangle(Pens.Red, 1, 1, 98, 98)
Case "DrawRectangle 2"
e.Graphics.DrawRectangle(Pens.Red, 0.501, 0.501, 98, 98)
Case "FillRectangle 1"
e.Graphics.FillRectangle(Brushes.Red, 1, 1, 98, 98)
Case "FillRectangle 2"
e.Graphics.FillRectangle(Brushes.Red, 1.1, 1.1, 98, 98)
Case "DrawEllipse"
e.Graphics.DrawEllipse(Pens.Red, 1, 1, 98, 98)
Case "FillEllipse"
e.Graphics.FillEllipse(Brushes.Red, 1, 1, 98, 98)
End Select
End Sub
Private Sub ComboBox1_TextChanged(ByVal sender As Object, ByVal e As
System.EventArgs) Handles ComboBox1.TextChanged
Panel1.Invalidate()
Select Case ComboBox1.Text
Case "DrawLine"
TextBox2.Text = "DrawLine with integer arguments: This method
works as expected."
Case "DrawRectangle 1"
TextBox2.Text = "DrawRectangle(Pens.Red, 1, 1, 98, 98): This
method does not work as expected. The rectangle is too big."
Case "DrawRectangle 2"
TextBox2.Text = "DrawRectangle(Pens.Red, 0.501, 0.501, 98,
98): This method does not work as expected. The rectangle is
positioned improperly and is too big."
Case "FillRectangle 1"
TextBox2.Text = "FillRectangle(Brushes.Red, 1, 1, 98, 98):
This method works as expected."
Case "FillRectangle 2"
TextBox2.Text = "FillRectangle(Brushes.Red, 1.1, 1.1, 98, 98):
This method does not work as expected. The rectangle is positioned
improperly."
Case "DrawEllipse"
TextBox2.Text = "DrawEllipse(Pens.Red, 1, 1, 98, 98): This
method does not work as expected. The ellipse is too big and is not
centered properly."
Case "FillEllipse"
TextBox2.Text = "FillEllipse(Brushes.Red, 1, 1, 98, 98): This
method does not work as expected. The ellipse is too small and is not
centered properly."
End Select
End Sub
End Class