locked
Drawing in zooming picturebox RRS feed

  • Question

  • Good morning,

    I'm using an image in a PictureBox and drawing on it with the MouseDown, MouseMove and MouseUp.

    When no zoom applied to the image, the "points", rectangles, lines and others are drawn correctly, but when I apply a zoom, the mouse coordinates X and Y that are captured through the MouseMove event are not correct, and the drawing elements are painted in a wrong place.

    How I can fix it?

    Thank you very much.
    Sunday, September 16, 2018 7:24 AM

All replies

  • How I can fix it?

    Thank you very much.

    Hi

    Well, to fix it, the first step would be to show the code which would help us to help you.


    Regards Les, Livingston, Scotland

    Sunday, September 16, 2018 10:49 AM
  • Hello
    So to start here is my personalized picturebox:

    Public Class zoomPic
        Inherits ScrollableControl
        Private _image As Image
        <Category("Appearance")>
        <Description("L'image à charger")>
        Public Property Image() As Image
            Get
                Return _image
            End Get
            Set
                _image = Value
                UpdateScaleFactor()
                Invalidate()
            End Set
        End Property
        Private _zoom As Single = 1.0
        '"Appearance"
        '"The zoom factor. Less than 1 to reduce. More than 1 to magnify."
        <Category("Appearance")>
        <Description("Le facteur de zoom Moins de 1 pour réduire. Plus que 1 pour agrandir.")>
        Public Property Zoom() As Single
            Get
                Return _zoom
            End Get
            Set
                If Value < 0 OrElse Value < 0.00001 Then
                    Value = 0.00001F
                End If
                _zoom = Value
                UpdateScaleFactor()
                Invalidate()
            End Set
        End Property
        Private Sub UpdateScaleFactor()
            If _image Is Nothing Then
                Me.AutoScrollMargin = Me.Size
            Else
                Me.AutoScrollMinSize = New Size(CInt(Me._image.Width * _zoom + 0.5F), CInt(Me._image.Height * _zoom + 0.5F))
            End If
        End Sub 'mise a jour de l'echelle
        Private _interpolationMode As InterpolationMode = InterpolationMode.High
        <Category("Appearance")>
        <Description("
    Le mode d'interpolation utilisé pour lisser le dessin")>
        Public Property InterpolationMode() As InterpolationMode
            Get
                Return _interpolationMode
            End Get
            Set
                _interpolationMode = Value
            End Set
        End Property
        Protected Overrides Sub OnPaintBackground(pevent As PaintEventArgs)
        End Sub ' ne rien faire
        Protected Overrides Sub OnPaint(e As PaintEventArgs)
            'si aucune image, ne dérange pas
            If _image Is Nothing Then
                MyBase.OnPaintBackground(e)
                Return
            End If
            'Mettre en place une matrice de zoom
            Dim mx As New Matrix(_zoom, 0, 0, _zoom, 0, 0)
            mx.Translate(Me.AutoScrollPosition.X / _zoom, Me.AutoScrollPosition.Y / _zoom)
            e.Graphics.Transform = mx
            e.Graphics.InterpolationMode = _interpolationMode
            e.Graphics.DrawImage(_image, New Rectangle(0, 0, Me._image.Width, Me._image.Height), 0, 0, _image.Width, _image.Height, GraphicsUnit.Pixel)
            MyBase.OnPaint(e)
        End Sub
     

    Then I go through a trackbar with such property: the min 1 and max 500 
    to zoom my picturebox so that to recover my zoom factor I go through the change in value of my trackbar as:

    ZPic1.Zoom = Me.TrackBar1.Value / 100

    The code for the drawings (Zpic1 is my personalized picturebox):

    Private Sub ZPic1_MouseDown(sender As Object, e As MouseEventArgs) Handles ZPic1.MouseDown
            undo.undoStack.Push(bmpPic.Clone)
            undo.redoStack.Clear()
            FaireToolStripMenuItem.Enabled = CBool(undo.undoStack.Count)
            DefaireToolStripMenuItem.Enabled = CBool(undo.redoStack.Count)
            drawFlag = True
            xDown = ZPic1.PointToClient(Cursor.Position).X
            yDown = ZPic1.PointToClient(Cursor.Position).Y
    
    
        End Sub
        Private Sub ZPic1_MouseMove(sender As Object, e As MouseEventArgs) Handles ZPic1.MouseMove
            If intToolSelected = 1 And drawFlag = True Then
                xDown = ZPic1.PointToClient(Cursor.Position).X
                yDown = ZPic1.PointToClient(Cursor.Position).Y
                undo.undoStack.Push(bmpPic.Clone)
                undo.redoStack.Clear()
                FaireToolStripMenuItem.Enabled = CBool(undo.undoStack.Count)
                DefaireToolStripMenuItem.Enabled = CBool(undo.redoStack.Count)
                LeGraphique.FillEllipse(New SolidBrush(Color.Red), xDown, yDown, intBrushSize, intBrushSize)
                ZPic1.Refresh()
            End If
    
        End Sub
    
        Private Sub ZPic1_MouseUp(sender As Object, e As MouseEventArgs) Handles ZPic1.MouseUp
            Dim brushFill As SolidBrush = New Drawing.SolidBrush(Color.RoyalBlue)
            Dim penLine As New Pen(Color.Green, intPenWidth)
    
            drawFlag = False
            xUp = ZPic1.PointToClient(Cursor.Position).X
            yUp = ZPic1.PointToClient(Cursor.Position).Y
    
            Select Case intToolSelected
                Case 2
                    LeGraphique.DrawLine(penLine, xDown, yDown, xUp, yUp)
                Case 4
                    dimSquare()
                    LeGraphique.DrawRectangle(penLine, intL, intT, intW, intW)
                Case 5
                    dimSquare()
                    LeGraphique.FillRectangle(brushFill, intL, intT, intW, intW)
                Case 6
                    dimRectangle()
                    LeGraphique.DrawRectangle(penLine, intL, intT, intW, intH)
                Case 7
                    dimRectangle()
                    LeGraphique.FillRectangle(brushFill, intL, intT, intW, intH)
                Case 8
                    dimCircle()
                    LeGraphique.DrawEllipse(penLine, intL, intT, intW, intW)
                Case 9
                    dimCircle()
                    LeGraphique.FillEllipse(brushFill, intL, intT, intW, intW)
                Case 10
                    dimEllipse()
                    LeGraphique.DrawEllipse(penLine, intL, intT, intW, intH)
                Case 11
                    dimEllipse()
                    LeGraphique.FillEllipse(brushFill, intL, intT, intW, intH)
            End Select
            ZPic1.Refresh()
        End Sub
    so I managed to zoom in but when I want to draw if I'm zoomed to 1x:
    I can draw well at the position of my mouse;
    but if my zoom is different from 1:
    when I draw the position of the mouse is shift

    Thank you for your help and your time.

    Sunday, September 16, 2018 11:27 AM
  • When you use PointToClient the coordinates do not get scaled.

    Here is a better way. See how the ScaleRatio is the same as your zoom factor more or less.

    Also this example does all the drawing in the paint event where the scale is set using transforms instead of a matrix but its the same thing.

    The example draws a rectangle with the mouse you can modify it to make your drawing object shapes. You zoom with the mouse wheel at the mouse pointer position etc.

    https://social.msdn.microsoft.com/Forums/vstudio/en-US/a95ea88e-588f-47c0-b8bc-a3a9fe8a7469/how-to-draw-to-scale-cad-with-gdi-and-vbnet?forum=vbgeneral

    Look it over and then ask questions. It is easier than trying to change the code you have.

    PS If you want to stay with your code then you need to multiply the pixel screen coordinates you are using by the zoom scale factor you use similar to what you see in the ClientToScale sub routine of the example.

    Sunday, September 16, 2018 11:54 AM