The code is posted below:
Private Sub Draw(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles Button3.Click
Dim g As Graphics
Dim sngScaleFactor As Single
g = PictureBox1.CreateGraphics()
g.Clear(PictureBox1.BackColor)
g.PageUnit = GraphicsUnit.Inch
Dim Points() As PointF = {New PointF(0, 0), New
PointF(CSng(TextBox3.Text), 0), New PointF(CSng
(TextBox3.Text), CSng(TextBox4.Text)), New PointF(0, CSng
(TextBox4.Text))}
path.Reset()
path.AddPolygon(Points)
g.DrawPath(New Pen(Color.Red, 1 / g.DpiX), path)
End Sub
Private Sub PictureBox1_MouseMove(ByVal sender As Object,
ByVal e As System.Windows.Forms.MouseEventArgs) Handles
PictureBox1.MouseMove
If path.IsVisible(e.X / PictureBox1.CreateGraphics
().DpiX, e.Y / PictureBox1.CreateGraphics.DpiY) Then
MsgBox("X - " & e.X.ToString & " Y - " &
e.Y.ToString)
End If
End Sub
Please stop grabbing the graphics out of the PictureBox I know that old
style VB encouraged you to do such awful things but that was wrong and this
is wronger.
One tip I'll give you is that you don't need PictureBox at-all because
you're not even using a picture. Use a panel instead and then use proper
event-driven code to do all the drawing and the mouse handling for you.
I prepared the following application to demonstrate the right way to do it
but I find to my horror that IsVisible only works with integer numbers and
rounds floating point input!!
If I put in a rectangle height with some fraction of an inch larger than 0.5
the hit test is valid to the next nearest rounded inch. So much for
resolution independance eh?? This is either a definite bug or my ignorance
of VB which constantly springs idiotic surprises like this on me.
Code after my sig...
--
Bob Powell [MVP]
C#, System.Drawing
September's edition of Well Formed is now available.
http://www.bobpowell.net/currentissue.htm
Answer those GDI+ questions with the GDI+ FAQ
http://www.bobpowell.net/gdiplus_faq.htm
----------------------------------------------------------------------------
---------------
Imports System.Drawing.Drawing2D
Public Class Form1
Inherits System.Windows.Forms.Form
Private pth As GraphicsPath
Private insquare As Boolean
#Region " Windows Form Designer generated code "
Public Sub New()
MyBase.New()
'This call is required by the Windows Form Designer.
InitializeComponent()
'Add any initialization after the InitializeComponent() call
End Sub
'Form overrides dispose to clean up the component list.
Protected Overloads Overrides Sub Dispose(ByVal disposing As Boolean)
If disposing Then
If Not (components Is Nothing) Then
components.Dispose()
End If
End If
MyBase.Dispose(disposing)
End Sub
'Required by the Windows Form Designer
Private components As System.ComponentModel.IContainer
'NOTE: The following procedure is required by the Windows Form Designer
'It can be modified using the Windows Form Designer.
'Do not modify it using the code editor.
Friend WithEvents TextBox1 As System.Windows.Forms.TextBox
Friend WithEvents TextBox2 As System.Windows.Forms.TextBox
Friend WithEvents Label1 As System.Windows.Forms.Label
Friend WithEvents Label2 As System.Windows.Forms.Label
Friend WithEvents Panel1 As System.Windows.Forms.Panel
<System.Diagnostics.DebuggerStepThrough()> Private Sub InitializeComponent()
Me.TextBox1 = New System.Windows.Forms.TextBox
Me.TextBox2 = New System.Windows.Forms.TextBox
Me.Label1 = New System.Windows.Forms.Label
Me.Label2 = New System.Windows.Forms.Label
Me.Panel1 = New System.Windows.Forms.Panel
Me.SuspendLayout()
'
'TextBox1
'
Me.TextBox1.Location = New System.Drawing.Point(56, 24)
Me.TextBox1.Name = "TextBox1"
Me.TextBox1.Size = New System.Drawing.Size(64, 20)
Me.TextBox1.TabIndex = 0
Me.TextBox1.Text = "0.5"
'
'TextBox2
'
Me.TextBox2.Location = New System.Drawing.Point(56, 48)
Me.TextBox2.Name = "TextBox2"
Me.TextBox2.Size = New System.Drawing.Size(64, 20)
Me.TextBox2.TabIndex = 1
Me.TextBox2.Text = "1.2"
'
'Label1
'
Me.Label1.Location = New System.Drawing.Point(8, 24)
Me.Label1.Name = "Label1"
Me.Label1.Size = New System.Drawing.Size(48, 23)
Me.Label1.TabIndex = 2
Me.Label1.Text = "Width"
'
'Label2
'
Me.Label2.Location = New System.Drawing.Point(8, 48)
Me.Label2.Name = "Label2"
Me.Label2.Size = New System.Drawing.Size(48, 23)
Me.Label2.TabIndex = 2
Me.Label2.Text = "Height"
'
'Panel1
'
Me.Panel1.Location = New System.Drawing.Point(144, 8)
Me.Panel1.Name = "Panel1"
Me.Panel1.Size = New System.Drawing.Size(432, 248)
Me.Panel1.TabIndex = 3
'
'Form1
'
Me.AutoScaleBaseSize = New System.Drawing.Size(5, 13)
Me.ClientSize = New System.Drawing.Size(592, 266)
Me.Controls.Add(Me.Panel1)
Me.Controls.Add(Me.Label1)
Me.Controls.Add(Me.TextBox2)
Me.Controls.Add(Me.TextBox1)
Me.Controls.Add(Me.Label2)
Me.Name = "Form1"
Me.Text = "Form1"
Me.ResumeLayout(False)
End Sub
#End Region
Private Sub TextBox2_TextChanged(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles TextBox2.TextChanged
If Not Me.pth Is Nothing Then
Me.pth.Dispose()
Me.pth = Nothing
End If
Try
Me.pth = New GraphicsPath
pth.AddRectangle(New RectangleF(0.5F, 0.5F, Single.Parse(Me.TextBox1.Text),
Single.Parse(Me.TextBox2.Text)))
Me.Panel1.Invalidate()
Catch
Finally
Me.Panel1.Invalidate()
End Try
End Sub
Private Sub TextBox1_TextChanged(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles TextBox1.TextChanged
If Not Me.pth Is Nothing Then
Me.pth.Dispose()
Me.pth = Nothing
End If
Try
Me.pth = New GraphicsPath
pth.AddRectangle(New RectangleF(0.5F, 0.5F, CSng(Me.TextBox1.Text),
CSng(Me.TextBox2.Text)))
Me.Panel1.Invalidate()
Catch
Finally
Me.Panel1.Invalidate()
End Try
End Sub
Private Sub Panel1_Paint(ByVal sender As Object, ByVal e As
System.Windows.Forms.PaintEventArgs) Handles Panel1.Paint
If pth Is Nothing Then
Return
End If
e.Graphics.PageUnit = GraphicsUnit.Inch
If insquare Then
e.Graphics.FillPath(Brushes.Red, pth)
Else
e.Graphics.FillPath(Brushes.Green, pth)
End If
End Sub
Private Sub Panel1_MouseMove(ByVal sender As Object, ByVal e As
System.Windows.Forms.MouseEventArgs) Handles Panel1.MouseMove
If pth Is Nothing Then
Return
End If
'the graphics for a panel is the same dpi as the form it sits on
Dim g As Graphics = CreateGraphics()
Dim dpix As Single = CSng(g.DpiX)
Dim dpiy As Single = CSng(g.DpiY)
g.Dispose() 'do that properly
Dim pf As New PointF(CSng(e.X) / dpix, CSng(e.Y) / dpiy)
System.Diagnostics.Trace.WriteLine(pf.ToString)
Dim oldone = Me.insquare
Me.insquare = Me.pth.IsVisible(pf)
If Me.insquare <> oldone Then
Me.Panel1.Invalidate()
End If
End Sub
End Class
"Matt" <matt_batcha@N0$PAMfenetech.com> wrote in message
news:143b01c37eb6$382fa4e0$a101...@phx.gbl...
First, thanks for you reply.
Could please explain why getting the graphics object is
not the correct way to do things or point me to an article
that I can read that explains it? I'm new to working with
GDI+. What I'm currently working is building a custom
user control that requires drawing to the screen.
Thanks Again....Matt
>.
>
1) Override OnPaint for your control/form/usercontrol (e.Graphics)
2) Handle the Paint event for a control such as a Panel per Bob's example
3) Use CreateGraphics() per Bob's example.
Different people will tell you different things about when to use what, and
you will find competing examples on MSDN. For example, a compact framework
game example I recently saw used CreateGraphics a lot, but most people
recommend you avoid CreateGraphics and use the OnPaint override and/or
handle paint events unless you have a good reason not to.
As you saw in Bob's example, make sure if you use CreateGraphics you dispose
the graphics object. If you override OnPaint, call the base class paint
unless you have a good reason not to. The rule of thumb is, if you find a
Dispose method in intellisense, and you created the object (it wasn't given
to you by an event handler, etc), you need to dispose it. You should also
dispose your GraphicsPath you are creating.
Given the same goal, people will have slight variations in their
implementations.
"Matt" <matt_batcha@N0$PAMfenetech.com> wrote in message
news:01c501c37ed1$f51255b0$a401...@phx.gbl...
Thanks for your reply.
I understand how to get the graphics object. The problem I
had earlier was getting the IsVisible method to work
correctly (ignoring the floating point rounding Bob
pointed out). In Bob's reply and example he said not to
use the picturebox's graphics object instead recommended
using the panel box. The code I displayed earlier was a
small test app that I had created to play around with
changing the page unit to inches. I'm modifying a custom
user control which draws to the screen. Currently it uses
pixels but I will be adding complexity and would prefer to
do everything inches. When I draw a 1x2 inch rectangle I
only "get a hit" when I'm over a small portion of the user
control.
Anyway I don't know if I'll even be able to stay with
using the page units as inches since the isvisible does
not correctly work with floating point numbers.
>.
>
Matt,
Windows is an event driven system in which things happen in a strict order
in response to the event stimulus. For an object to draw itself outside of
that synchronized loop is bad enough but when you go in through a back-door,
steal the graphics of and rudely paint on some other control outside of the
WM_PAINT event then you open yourself up for problems. Specifically, the
bits you paint are only good until the next Paint event comes along. You
have no way of determinig in advance when or why the paint event will be
kicked off so you'll never reliably be able to display a graphic and have it
remain in place for a known period (ie as long as you need it). The biggest
complaint of programmers who use this dubious technoque is "I drew a bunch
of stuff on my PictureBox and every time a window moves in front of it it
all disappears". PictureBox bye the way is the most misused control in the
known universe and is almost totally unecessary.
The *only* time you should paint on the screen is when WM_PAINT fires and
the events kick off from that. You can override the OnPaint protected method
if you want to do it properly or you can handle the Paint event. In both
cases, the Graphics to paint on is handed to you in an event argument and
you should *never* need to use CreateGraphics inside a drawing loop.
In my example, I got the Graphics of the control, not to paint upon the
screen but to get some information that I knew would be provided. No
painting was done outside of the Paint event and the graphics was disposed
of immediately.
Following the event driven architecture strictly is perhaps a little more
difficult and requires more discipline than just banging away in what seems
to be a logical manner, after all when you click the mouse you want to draw
something.. yes?.. Well actually no! The answer really is that you set up
conditions within your program so that when the Paint event comes along, you
draw what happened during the click.
The first edition of Well Formed has a complete drawing package that
illustrates how to perform mouse event management and drawing in accordance
with the Paint event. http://www.bobpowell.net/August2003.htm
Sorry to bang on about this but so many people cause themselves pain that
they don't need and then come here and ask questions about it.
Bob.
--
Bob Powell [MVP]
C#, System.Drawing
September's edition of Well Formed is now available.
http://www.bobpowell.net/currentissue.htm
Answer those GDI+ questions with the GDI+ FAQ
http://www.bobpowell.net/gdiplus_faq.htm
"Matt" <matt_batcha@N0$PAMfenetech.com> wrote in message
news:01c501c37ed1$f51255b0$a401...@phx.gbl...
I need to investigate that rounding thing. It'll give me sleepless nights
now.
--
Bob Powell [MVP]
C#, System.Drawing
September's edition of Well Formed is now available.
http://www.bobpowell.net/currentissue.htm
Answer those GDI+ questions with the GDI+ FAQ
http://www.bobpowell.net/gdiplus_faq.htm
"Matt" <matt_batcha@N0$PAMfenetech.com> wrote in message
news:0f5201c37eda$bfbe0ea0$a001...@phx.gbl...
Thanks for the explanation. I will be subscribing to Well
Formed.
Have a good weekend.
Matt
>.
>
Cheers,
Paul
"Bob Powell [MVP]" <bob@_spamkiller_bobpowell.net> wrote in message
news:OTQpU2rf...@TK2MSFTNGP12.phx.gbl...
Widen takes a boundary and effectively strokes it with a pen making a region
with voids where the interior used to be and a band around the outside the
same width as the pen including any end-caps or miters the pen has.
If you want to widen a path and detect the middle of it you need to create a
region from the original, perform a widen, greate a region from the widened
path then a union to merge the two regions before finally hit-testing the
result with Region.IsVisible.
--
Bob Powell [MVP]
C#, System.Drawing
September's edition of Well Formed is now available.
http://www.bobpowell.net/currentissue.htm
Answer those GDI+ questions with the GDI+ FAQ
http://www.bobpowell.net/gdiplus_faq.htm
"Paul Hetherington" <phethe...@visualstatement.com> wrote in message
news:OYyvsQw...@tk2msftngp13.phx.gbl...
It is still annoying that the .IsVisible takes two singles but only seems to
work to the nearest integer regardless.
Cheers,
Paul
"Bob Powell [MVP]" <bob@_spamkiller_bobpowell.net> wrote in message
news:%23PpLrE1...@TK2MSFTNGP10.phx.gbl...