Solved

VB.NET Problem with pictureBox Paint event

Posted on 2004-08-17
6
7,174 Views
Last Modified: 2012-05-05
Hi experts. I'm trying to upgrade VB6 to VB.NET. As we know, a pictureBox in VB.NET hase no autoRedraw and instead we need to use Paint event.
I could not put my DrawLine code in the paint event since my application draws different curves in different manners (depending on the options of the user)
I've asked this question before at :http://www.experts-exchange.com/Programming/Programming_Languages/Dot_Net/VB_DOT_NET/Q_21070801.html

And Idle-Mind found a good solution using an interface. Now When I try to run the drawing from another window Form, the process fails without an error.(The process works in a single form)
You need the code to understand so here I made a very very simple code:(just copy & paste)

'In the Module:
    Public Interface GraphObject
        Sub Paint(ByRef g As Graphics)
    End Interface

    Public Class LineObject
        Implements GraphObject

        Private pointA As Point
        Private pointB As Point

        Public Sub New(ByVal ptA As Point, ByVal ptB As Point)
            pointA = ptA
            pointB = ptB
        End Sub

        Public Sub Paint(ByRef g As Graphics) Implements GraphObject.Paint
            g.DrawLine(Pens.Black, pointA, pointB)
        End Sub
    End Class

'---------In Form1:
Public Class Form1
    Inherits System.Windows.Forms.Form

#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 Button1 As System.Windows.Forms.Button
    Friend WithEvents PictureBox1 As System.Windows.Forms.PictureBox
    <System.Diagnostics.DebuggerStepThrough()> Private Sub InitializeComponent()
        Me.Button1 = New System.Windows.Forms.Button
        Me.PictureBox1 = New System.Windows.Forms.PictureBox
        Me.SuspendLayout()
        '
        'Button1
        '
        Me.Button1.Location = New System.Drawing.Point(8, 8)
        Me.Button1.Name = "Button1"
        Me.Button1.Size = New System.Drawing.Size(80, 24)
        Me.Button1.TabIndex = 0
        Me.Button1.Text = "Add Line"
        '
        'PictureBox1
        '
        Me.PictureBox1.Anchor = CType((((System.Windows.Forms.AnchorStyles.Top Or System.Windows.Forms.AnchorStyles.Bottom) _
                    Or System.Windows.Forms.AnchorStyles.Left) _
                    Or System.Windows.Forms.AnchorStyles.Right), System.Windows.Forms.AnchorStyles)
        Me.PictureBox1.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle
        Me.PictureBox1.Location = New System.Drawing.Point(8, 40)
        Me.PictureBox1.Name = "PictureBox1"
        Me.PictureBox1.Size = New System.Drawing.Size(280, 224)
        Me.PictureBox1.TabIndex = 1
        Me.PictureBox1.TabStop = False
        '
        'Form1
        '
        Me.AutoScaleBaseSize = New System.Drawing.Size(5, 13)
        Me.ClientSize = New System.Drawing.Size(292, 266)
        Me.Controls.Add(Me.PictureBox1)
        Me.Controls.Add(Me.Button1)
        Me.Name = "Form1"
        Me.Text = "Peristent Graphics via Classes"
        Me.ResumeLayout(False)

    End Sub

#End Region

    Private Sub PictureBox1_Paint(ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles PictureBox1.Paint
        Dim go As GraphObject
        Dim f2 As New Form2

        For Each go In f2.graphObjects
            go.Paint(e.Graphics)
        Next
    End Sub

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        Dim form2 As New Form2
        form2.Show()
    End Sub

End Class
'------In Form2:
Public Class Form2
    Inherits System.Windows.Forms.Form

#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 Button1 As System.Windows.Forms.Button
    <System.Diagnostics.DebuggerStepThrough()> Private Sub InitializeComponent()
        Me.Button1 = New System.Windows.Forms.Button
        Me.SuspendLayout()
        '
        'Button1
        '
        Me.Button1.Location = New System.Drawing.Point(72, 16)
        Me.Button1.Name = "Button1"
        Me.Button1.Size = New System.Drawing.Size(72, 48)
        Me.Button1.TabIndex = 0
        Me.Button1.Text = "Draw"
        '
        'Form2
        '
        Me.AutoScaleBaseSize = New System.Drawing.Size(5, 13)
        Me.ClientSize = New System.Drawing.Size(216, 86)
        Me.Controls.Add(Me.Button1)
        Me.Name = "Form2"
        Me.Text = "Draw"
        Me.ResumeLayout(False)

    End Sub

#End Region
    Private rnd As New Random(DateTime.Now().Second)
    Public graphObjects As New ArrayList

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click


        Dim x1, y1, x2, y2 As Integer
        x1 = 0
        y1 = 0
        x2 = 100
        y2 = 100

        Dim l As New LineObject(New Point(x1, y1), New Point(x2, y2))
        graphObjects.Add(l)
        Dim Form1 As New Form1
        Form1.PictureBox1.Refresh()
        Me.Hide()
    End Sub
End Class
0
Comment
Question by:kouroshparsa
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 4
  • 2
6 Comments
 
LVL 86

Accepted Solution

by:
Mike Tomlinson earned 200 total points
ID: 11825833
Try this out:

' --------------------------------------------------------------------------------------
' Form1
' --------------------------------------------------------------------------------------

Public Class Form1
    Inherits System.Windows.Forms.Form

#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 Button1 As System.Windows.Forms.Button
    Friend WithEvents PictureBox1 As System.Windows.Forms.PictureBox
    <System.Diagnostics.DebuggerStepThrough()> Private Sub InitializeComponent()
        Me.Button1 = New System.Windows.Forms.Button
        Me.PictureBox1 = New System.Windows.Forms.PictureBox
        Me.SuspendLayout()
        '
        'Button1
        '
        Me.Button1.Location = New System.Drawing.Point(8, 8)
        Me.Button1.Name = "Button1"
        Me.Button1.Size = New System.Drawing.Size(80, 24)
        Me.Button1.TabIndex = 0
        Me.Button1.Text = "Add Line"
        '
        'PictureBox1
        '
        Me.PictureBox1.Anchor = CType((((System.Windows.Forms.AnchorStyles.Top Or System.Windows.Forms.AnchorStyles.Bottom) _
                    Or System.Windows.Forms.AnchorStyles.Left) _
                    Or System.Windows.Forms.AnchorStyles.Right), System.Windows.Forms.AnchorStyles)
        Me.PictureBox1.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle
        Me.PictureBox1.Location = New System.Drawing.Point(8, 40)
        Me.PictureBox1.Name = "PictureBox1"
        Me.PictureBox1.Size = New System.Drawing.Size(280, 224)
        Me.PictureBox1.TabIndex = 1
        Me.PictureBox1.TabStop = False
        '
        'Form1
        '
        Me.AutoScaleBaseSize = New System.Drawing.Size(5, 13)
        Me.ClientSize = New System.Drawing.Size(292, 266)
        Me.Controls.Add(Me.PictureBox1)
        Me.Controls.Add(Me.Button1)
        Me.Name = "Form1"
        Me.Text = "Peristent Graphics via Classes"
        Me.ResumeLayout(False)

    End Sub

#End Region

    Public graphObjects As New ArrayList
    Private WithEvents f2 As Form2

    Private Sub PictureBox1_Paint(ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles PictureBox1.Paint
        Dim go As GraphObject

        For Each go In graphObjects
            go.Paint(e.Graphics)
        Next
    End Sub

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        If f2 Is Nothing Then
            f2 = New Form2
            f2.f1 = Me
        End If
        f2.Show()
    End Sub

    Private Sub f2_Closed(ByVal sender As Object, ByVal e As System.EventArgs) Handles f2.Closed
        f2 = Nothing
    End Sub

    Private Sub Form1_Closing(ByVal sender As Object, ByVal e As System.ComponentModel.CancelEventArgs) Handles MyBase.Closing
        If Not (f2 Is Nothing) Then
            f2.Dispose()
            f2 = Nothing
        End If
    End Sub

End Class

' --------------------------------------------------------------------------------------
' Form2
' --------------------------------------------------------------------------------------
Public Class Form2
    Inherits System.Windows.Forms.Form

#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 Button1 As System.Windows.Forms.Button
    <System.Diagnostics.DebuggerStepThrough()> Private Sub InitializeComponent()
        Me.Button1 = New System.Windows.Forms.Button
        Me.SuspendLayout()
        '
        'Button1
        '
        Me.Button1.Location = New System.Drawing.Point(72, 16)
        Me.Button1.Name = "Button1"
        Me.Button1.Size = New System.Drawing.Size(72, 48)
        Me.Button1.TabIndex = 0
        Me.Button1.Text = "Draw"
        '
        'Form2
        '
        Me.AutoScaleBaseSize = New System.Drawing.Size(5, 13)
        Me.ClientSize = New System.Drawing.Size(216, 86)
        Me.Controls.Add(Me.Button1)
        Me.Name = "Form2"
        Me.Text = "Draw"
        Me.ResumeLayout(False)

    End Sub

#End Region

    Public f1 As Form1

    Private rnd As New Random(DateTime.Now().Second)

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        Dim x1, y1, x2, y2 As Integer
        x1 = rnd.NextDouble() * f1.PictureBox1.Width
        y1 = rnd.NextDouble() * f1.PictureBox1.Height
        x2 = rnd.NextDouble() * f1.PictureBox1.Width
        y2 = rnd.NextDouble() * f1.PictureBox1.Height

        Dim l As New LineObject(New Point(x1, y1), New Point(x2, y2))
        f1.graphObjects.Add(l)
        f1.PictureBox1.Refresh()
        Me.Hide()
    End Sub

End Class
0
 
LVL 2

Author Comment

by:kouroshparsa
ID: 11827209
Thanks Idle-Mind. The sample woks very well; however, the real problem is my complicated program.
Now I'm facing another problem without an error and without any graphing action.
I found the problem:
Dim gr As Graphics = FormGraph.DefInstance.pictureBoxGraph.CreateGraphics
Dim XMIN As Double
Dim XMAX As Double
Dim YMIN As Double
Dim YMAX As Double
'--------------------Setting Scale:
XMIN = FormGraph.DefInstance.GraphScaleLeft
XMAX = XMIN + FormGraph.DefInstance.GraphScaleWidth
YMAX = FormGraph.DefInstance.GraphScaleTop
YMIN = YMAX - FormGraph.DefInstance.GraphScaleHeight
SetScale(gr, FormGraph.DefInstance.pictureBoxGraph.Width, FormGraph.DefInstance.pictureBoxGraph.Height, XMIN, XMAX, YMAX, YMIN)
'------------------Graphing:
 Dim l As New LineObject(New Point(x1, y1), New Point(x2, y2))
frmGraph.graphObjects.Add(l)
'=======================


if x1=0 y1=0 and x2=100 y2=100 it does draw a line, but the problem is that I've changed the scale of "gr" which refers to the pictureBox but drawing is done on the object!

Apparently I should change the scale of the pictureBox somewhere else (either in module or in the paint event)
Please help me with that.
By the way, putting "Dim l As New LineObject..." in a loop with 400 iterations is not very good but work!
0
 
LVL 2

Author Comment

by:kouroshparsa
ID: 11835828
If you have any improving idea about the following, please let me know:
The main problem with the code is putting "Dim l as New LineObject" in a loop. By the way, since I want to handle big numbers, I can not use "Point(x1,y1)" so I'd change it to Double

Also, about the scale problem, let's clerify:
I put a method named SetScale in the module to change the scale to real graphing scale:
================
Public Sub SetScale(ByVal gr As Graphics, ByVal gr_width As Integer, ByVal gr_height As Integer, ByVal left_x As Single, ByVal right_x As Single, ByVal top_y As Single, ByVal bottom_y As Single)
' Set transformations for the Graphics object
' so its coordinate system matches the one specified.

gr.ResetTransform()

' Scale so the viewport's width and height
' map to the Graphics object's width and height.
gr.ScaleTransform( _
gr_width / (right_x - left_x), _
gr_height / (bottom_y - top_y))
' object's origin.
gr.TranslateTransform(-left_x, -top_y)
End Sub
=============================
and I call that in the LineObject class (in module):
======================
Public Sub Paint(ByRef g As Graphics) Implements GraphObject.Paint

SetScale(g, FormGraph.DefInstance.pictureBoxGraph.Width, FormGraph.DefInstance.pictureBoxGraph.Height, pointA.X, pointA.Y, pointB.X, pointB.Y)

g.DrawLine(Pens.Black, pointA, pointB)
End Sub
========================
It still does not work !
Please feel free to comment on anything.
0
Technology Partners: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
LVL 2

Author Comment

by:kouroshparsa
ID: 11856340
Hi Idle-Mind. Thanks to your good code.
I finally fixed all the problems myself and I'm posting this in case you may care.
I used to receive errors saying "Engine error" or "invalid parameter"...
The problem was that I disposed the graphic object at the end of the drawing process in the paint sub (in the module).
Normally it is ligal, but since Idle-Mind has used an interface, I should not dispose it !!! The debugging was very tough since it displayed that the error happend in a different place(not in module) !

By the way, in your first code, in the module you had some empty subs:
    Private Sub New()
    End Sub
I ignored that & I'm fine without it...What was your purpose?

Idle-Mind, about the idea of using "paths," I'm not sure how VB.NET manages memory with that. Do you know whether it's safe to have 100 different paths (every path is made by 400 lines)???
Cheers.
0
 
LVL 86

Expert Comment

by:Mike Tomlinson
ID: 11857166
By making the New() sub private, you prevent the user from creating an instance of your application using the default constructor like this:

    Dim c As someClass = New someClass()

You cannot create an instance of a class using the default contructor if it is private.  The reason for doing this is to force the user to pass in some kind of variable:

    Public Class someClass

        Private tpb As PictureBox

        ' Disable default consrtuctor
        Private Sub New()
        End Sub

        ' Force user to create in instance by passing in some kind of parameter
        Public Sub New(ByVal targetPictureBox As PictureBox)
            tpb = targetPictureBox
        End Sub

    End Class

So in the above class you can only create instances that receive a reference to a PictureBox:

    Dim c As someClass = New someClass(PictureBox1)

As far as Paths are concerned, I have never tried using them on the scale you are suggesting.  I used them once in an app that stored objects (lines, polygons, curves, etc) and it worked very well.  At most, I had about 50 objects onscreen at once with between 2 and 15 "lines" per path.

Regards,

Idle_Mind
0
 
LVL 2

Author Comment

by:kouroshparsa
ID: 11857672
That is a great explanation. Thanks a lot.
With the idea of using an interface, new issues are occurred for me.
A new problem is streching the picture when resizing...
I would be happy if you take a look at:

http://www.experts-exchange.com/Programming/Programming_Languages/Dot_Net/VB_DOT_NET/Q_21098910.html

Cheers
Have fun
0

Featured Post

Free Tool: ZipGrep

ZipGrep is a utility that can list and search zip (.war, .ear, .jar, etc) archives for text patterns, without the need to extract the archive's contents.

One of a set of tools we're offering as a way to say thank you for being a part of the community.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Article by: Kraeven
Introduction Remote Share is a simple remote sharing tool, enabling you to see, add and remove remote or local shares. The application is written in VB.NET targeting the .NET framework 2.0. The source code and the compiled programs have been in…
Introduction When many people think of the WebBrowser (http://msdn.microsoft.com/en-us/library/2te2y1x6%28v=VS.85%29.aspx) control, they immediately think of a control which allows the viewing and navigation of web pages. While this is true, it's a…
A short tutorial showing how to set up an email signature in Outlook on the Web (previously known as OWA). For free email signatures designs, visit https://www.mail-signatures.com/articles/signature-templates/?sts=6651 If you want to manage em…
In an interesting question (https://www.experts-exchange.com/questions/29008360/) here at Experts Exchange, a member asked how to split a single image into multiple images. The primary usage for this is to place many photographs on a flatbed scanner…

737 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question