none
DefWndProc resize picturebox RRS feed

  • Question

  • Hi,

    I am working on the code provided by tommytwotrain (see link below).

    https://social.msdn.microsoft.com/Forums/vstudio/en-US/52f31c56-f53d-4352-bab0-75287a2cb76f/place-rectangle-on-image-and-move?forum=vbgeneral#62a24c8b-3ce6-4701-9df1-3def4c781830

    He provided two ways to do it, but I am trying to work with the second one where he is using DefWndProc.

    Unfortunately, I can't resize the Bottom-Right corner keeping the ratio Width/Height constant.

    Is there a way to do it or should I forget about it with DefWndProc method?

    Thanks,

    JLuc01

    Sunday, March 25, 2018 9:51 AM

Answers

  • I think I got it.

    I need to put some code  in the OnResize event (Logic! Isn't it?).

    I am working on it now.

    • Marked as answer by JLuc01 Sunday, March 25, 2018 2:53 PM
    Sunday, March 25, 2018 2:47 PM
  •  There is no built in method or property to do that for you.  It is something you would need to implement in your code yourself by adjusting the width and/or height of the 'GlassWindow' as it is being resized.  It would not matter which method you use that Tom showed you,  you still have to implement it into the code yourself.

    If you say it can`t be done then i`ll try it

    • Marked as answer by JLuc01 Sunday, March 25, 2018 2:53 PM
    Sunday, March 25, 2018 1:52 PM

All replies

  • For a movable/sizable PictureBox, this works for me :

    (and to control the size on Bottom-Right, you can add WM_SIZING and test if m.WParam = WMSZ_BOTTOMRIGHT)

    Protected Overrides Sub WndProc(ByRef m As Message)
        If (m.Msg = WM_NCHITTEST) Then
            Dim nHitTest As Integer = DefWindowProc(m.HWnd, m.Msg, m.WParam, m.LParam)
            Select Case nHitTest
                Case HTLEFT To HTBOTTOMRIGHT                   
                    m.Result = New IntPtr(nHitTest)
                Case Else
                    m.Result = New IntPtr(HTCAPTION)
            End Select           
        Else
            MyBase.WndProc(m)
        End If
    End Sub
    
    Protected Overrides ReadOnly Property CreateParams() As CreateParams
        Get
            Dim params As CreateParams = MyBase.CreateParams
            params.Style += &H40000L
            Return params
        End Get
    End Property

    Sunday, March 25, 2018 11:53 AM
  • Thank you for your reply, but you lost me.

    Below is the code I am using (On a form: one picturebox (pbMyPict) and 2 buttons (btnLoad and btnSave)) . The issue is: I don't know how to resize the Bottom-Right corner keeping the ratio Width/Height constant during the move of the mouse. I am not sure it is possible considering how it is working, but I am certainly not an expert with this DefWndProc method.

    I think I found another way to do it with one PictureBox and a Rectangle, but I prefer this way with 2 PictureBoxes. Unfortunately, I don't find easy to use DefWndProc method.

    If you can adapt your code with what I did, it will be perfect.

    Thanks,

    JLuc01

    Imports System.IO
    Imports System.Drawing.Imaging
    
    Public Class frmImageCroping
        Public resizedImage As Image
        Private Glass As New GlassWindow
        Public dRatioPictureWH As Double
    
        Private Sub btnLoad_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnLoad.Click
            ' Load Picture with pixel size and ratio in the title of the Form
            Dim ofd1 As New OpenFileDialog
            Dim result As DialogResult = ofd1.ShowDialog
            If result = Windows.Forms.DialogResult.OK Then
                If (ofd1.FileName IsNot Nothing) Or (ofd1.FileName <> String.Empty) Then
                    Dim iWidthPX As Integer = Image.FromFile(ofd1.FileName).Width
                    Dim iHeightPX As Integer = Image.FromFile(ofd1.FileName).Height
                    dRatioPictureWH = iWidthPX / iHeightPX
                    Me.Text = iWidthPX & " x " & iHeightPX & " pixels - (Ratio: " & dRatioPictureWH.ToString("0.000") & ")"
                    ' Maximum size of the PictureBox is 400x400px
                    If iWidthPX > iHeightPX Then
                        If iWidthPX > 400 Then pbMyPict.Width = 400 Else MsgBox("ErrorSize")
                        pbMyPict.Height = 400 / dRatioPictureWH
                    Else
                        If iHeightPX > 400 Then pbMyPict.Height = 400 Else MsgBox("ErrorSize")
                        pbMyPict.Width = 400 * dRatioPictureWH
                    End If
                    ' Selected Picture in the PictureBox
                    pbMyPict.BackgroundImage = Image.FromFile(ofd1.FileName)
                    pbMyPict.BackgroundImageLayout = ImageLayout.Stretch
                    ' Resize and Save the image in a Stream for use in GlassWindow class
                    Dim memStream As MemoryStream = New MemoryStream
                    resizedImage = ResizeImage(ofd1.FileName, memStream, pbMyPict.Width, pbMyPict.Height)
                    resizedImage.Save(memStream, ImageFormat.Jpeg)
                End If
            End If
            ' GlassWindow
            pbMyPict.Controls.Add(Glass)
            With Glass
                .Size = New Size(100, 100)
                .Location = New Point(10, 10)
                .ForeColor = Color.White
            End With
        End Sub
    
        Private Sub btnSave_Click(ByVal sender As Object, ByVal e As EventArgs) Handles btnSave.Click
            Glass.BackgroundImage.Save("c:\bitmaps\test.jpg", System.Drawing.Imaging.ImageFormat.Jpeg)
        End Sub
    
        Private Sub pbMyPict_Paint(ByVal sender As Object, ByVal e As PaintEventArgs) Handles pbMyPict.Paint
            'draw the cloudy background
            e.Graphics.FillRectangle(New SolidBrush(Color.FromArgb(100, 255, 255, 255)), Me.ClientRectangle)
        End Sub
    
        Public Function ResizeImage(ByVal ImagePath As String, ByVal SavePath As Stream, ByVal xWidth As Integer, ByVal yHeight As Integer) As Image
            ' http://www.vbforums.com/showthread.php?550637-Reduce-file-size-of-images-(bmp-s-jpg-s-)
            Dim bm As New Bitmap(ImagePath)
            Dim width As Integer = Val(xWidth)
            Dim height As Integer = Val(yHeight)
            Dim thumb As New Bitmap(Width, Height)
            Using g As Graphics = Graphics.FromImage(thumb)
                g.InterpolationMode = Drawing2D.InterpolationMode.HighQualityBicubic
                g.DrawImage(bm, New Rectangle(0, 0, width, height), New Rectangle(0, 0, bm.Width, bm.Height), GraphicsUnit.Pixel)
                thumb.Save(SavePath, System.Drawing.Imaging.ImageFormat.Jpeg)
            End Using
            Return thumb
        End Function
    
    End Class
    
    Public Class GlassWindow
        Inherits PictureBox ' Control
    
        Private Const WM_NCLBUTTONDOWN As Integer = 161 '&HA1
        Private Const HTCAPTION As Integer = 2
        Private Const HTLEFT As Integer = 10
        Private Const HTRIGHT As Integer = 11
        Private Const HTTOP As Integer = 12
        Private Const HTTOPLEFT As Integer = 13
        Private Const HTTOPRIGHT As Integer = 14
        Private Const HTBOTTOM As Integer = 15
        Private Const HTBOTTOMLEFT As Integer = 16
        Private Const HTBOTTOMRIGHT As Integer = 17
    
        Private Const WM_NCHITTEST As Integer = 132
    
        Public Sub New()
            Me.Cursor = Cursors.SizeAll
        End Sub
    
        Protected Overrides Sub OnPaint(ByVal e As System.Windows.Forms.PaintEventArgs)
            Dim r As Rectangle = Me.ClientRectangle
            r.Location = Me.Location
            'get the glass background from the parent 
            Using bmp As New Bitmap(r.Width, r.Height), g As Graphics = Graphics.FromImage(bmp)
                'g.DrawImage(Me.Parent.BackgroundImage, Me.ClientRectangle, r, GraphicsUnit.Pixel)
                g.DrawImage(frmImageCroping.resizedImage, Me.ClientRectangle, r, GraphicsUnit.Pixel)
                Me.BackgroundImage = bmp.Clone
            End Using
            'draw the border
            e.Graphics.DrawRectangle(New Pen(Me.ForeColor, 3), Me.ClientRectangle)
            MyBase.OnPaint(e)
        End Sub
    
        Protected Overrides Sub OnMouseDown(ByVal e As System.Windows.Forms.MouseEventArgs)
            Select Case Me.Cursor
                Case Cursors.SizeAll
                    Me.Capture = False
                    Me.DefWndProc(Message.Create(Me.Handle, WM_NCLBUTTONDOWN, New IntPtr(HTCAPTION), IntPtr.Zero))
                Case Cursors.PanWest()
                    Me.Capture = False
                    Me.DefWndProc(Message.Create(Me.Handle, WM_NCLBUTTONDOWN, New IntPtr(HTLEFT), IntPtr.Zero))
                Case Cursors.PanEast()
                    Me.Capture = False
                    Me.DefWndProc(Message.Create(Me.Handle, WM_NCLBUTTONDOWN, New IntPtr(HTRIGHT), IntPtr.Zero))
                Case Cursors.PanNorth
                    Me.Capture = False
                    Me.DefWndProc(Message.Create(Me.Handle, WM_NCLBUTTONDOWN, New IntPtr(HTTOP), IntPtr.Zero))
                Case Cursors.PanNW
                    Me.Capture = False
                    Me.DefWndProc(Message.Create(Me.Handle, WM_NCLBUTTONDOWN, New IntPtr(HTTOPLEFT), IntPtr.Zero))
                Case Cursors.PanNE
                    Me.Capture = False
                    Me.DefWndProc(Message.Create(Me.Handle, WM_NCLBUTTONDOWN, New IntPtr(HTTOPRIGHT), IntPtr.Zero))
                Case Cursors.PanSouth
                    Me.Capture = False
                    Me.DefWndProc(Message.Create(Me.Handle, WM_NCLBUTTONDOWN, New IntPtr(HTBOTTOM), IntPtr.Zero))
                Case Cursors.PanSW
                    Me.Capture = False
                    Me.DefWndProc(Message.Create(Me.Handle, WM_NCLBUTTONDOWN, New IntPtr(HTBOTTOMLEFT), IntPtr.Zero))
                Case Cursors.PanSE
                    Me.Capture = False
                    Me.DefWndProc(Message.Create(Me.Handle, WM_NCLBUTTONDOWN, New IntPtr(HTBOTTOMRIGHT), IntPtr.Zero))
            End Select
            MyBase.OnMouseDown(e)
        End Sub
    
        Protected Overrides Sub OnMouseMove(ByVal e As System.Windows.Forms.MouseEventArgs)
    
            If Me.Location.X < 0 Then Me.Location = New Point(0, Me.Location.Y)
            If Me.Location.Y < 0 Then Me.Location = New Point(Me.Location.X, 0)
    
            If Me.Location.X + Me.Width > frmImageCroping.pbMyPict.Width Then Me.Location = New Point(frmImageCroping.pbMyPict.Width - Me.Width, Me.Location.Y)
            If Me.Location.Y + Me.Height > frmImageCroping.pbMyPict.Height Then Me.Location = New Point(Me.Location.X, frmImageCroping.pbMyPict.Height - Me.Height)
    
            Select Case True
                Case e.Y < 10                                       ' TOP (Y coordinate)
                    Select Case True
                        Case e.X < 10                               ' TOP-LEFT edge
                            Me.Cursor = Cursors.PanNW
                        Case e.X > Me.ClientSize.Width - 10         ' TOP-RIGHT edge
                            Me.Cursor = Cursors.PanNE
                        Case Else                                   ' TOP edge
                            Me.Cursor = Cursors.PanNorth
                    End Select
                Case e.Y > Me.ClientSize.Height - 10                ' BOTTOM (Y coordinate)
                    Select Case True
                        Case e.X < 10                               ' BOTTOM-LEFT edge
                            Me.Cursor = Cursors.PanSW
                        Case e.X > Me.ClientSize.Width - 10         ' BOTTOM-RIGHT edge
                            Me.Cursor = Cursors.PanSE
                        Case Else                                   ' BOTTOM edge
                            Me.Cursor = Cursors.PanSouth
                    End Select
                Case e.X < 10                                       ' LEFT edge (X coordinate)
                    Me.Cursor = Cursors.PanWest
                Case e.X > Me.ClientSize.Width - 10                 ' RIGHT edge (X coordinate)
                    Me.Cursor = Cursors.PanEast
                Case Else                                           ' NO edge
                    Me.Cursor = Cursors.SizeAll
            End Select
    
            MyBase.OnMouseMove(e)
        End Sub
    
        Protected Overrides Sub OnMove(ByVal e As System.EventArgs)
            Me.Invalidate()
            MyBase.OnMove(e)
        End Sub
    
        Protected Overrides Sub OnResize(ByVal e As System.EventArgs)
            Me.Invalidate()
            MyBase.OnResize(e)
        End Sub
    
    End Class
    

    Sunday, March 25, 2018 12:34 PM
  •  There is no built in method or property to do that for you.  It is something you would need to implement in your code yourself by adjusting the width and/or height of the 'GlassWindow' as it is being resized.  It would not matter which method you use that Tom showed you,  you still have to implement it into the code yourself.

    If you say it can`t be done then i`ll try it

    • Marked as answer by JLuc01 Sunday, March 25, 2018 2:53 PM
    Sunday, March 25, 2018 1:52 PM
  • Ok. I think I understand your comment. But, for example, this code below allow me to keep the WindowGlass inside the other PictureBox.

        Protected Overrides Sub OnMouseMove(ByVal e As System.Windows.Forms.MouseEventArgs)
    
            If Me.Location.X < 0 Then Me.Location = New Point(0, Me.Location.Y)
            If Me.Location.Y < 0 Then Me.Location = New Point(Me.Location.X, 0)
    
            If Me.Location.X + Me.Width > frmImageCroping.pbMyPict.Width Then Me.Location = New Point(frmImageCroping.pbMyPict.Width - Me.Width, Me.Location.Y)
            If Me.Location.Y + Me.Height > frmImageCroping.pbMyPict.Height Then Me.Location = New Point(Me.Location.X, frmImageCroping.pbMyPict.Height - Me.Height)

    But, when I am moving the WindowGlass, it goes outside of the other PictureBox and come back to it place (where I want it) only after MouseUp.

    I think I may have to reorganize this code and try to put it to the right event, just surprise that the 4 lines of code above are not to the right place, or maybe the issue is coming from the code position in the OnMouseDown event.

    Sunday, March 25, 2018 2:26 PM
  • I also tried this code in the OnMouseMove event:

    Case e.X > Me.ClientSize.Width - 10         ' BOTTOM-RIGHT edge
       Me.Cursor = Cursors.PanSE
    
       If Me.Height > Me.Width Then Me.Width = Me.Height * frmImageCroping.dRatioPictureWH
       If Me.Width > Me.Height Then Me.Height = Me.Width / frmImageCroping.dRatioPictureWH
    
    It is working, but once again, only after the I release the button of the mouse, but not during the movement of the mouse.

    Sunday, March 25, 2018 2:38 PM
  • I think I got it.

    I need to put some code  in the OnResize event (Logic! Isn't it?).

    I am working on it now.

    • Marked as answer by JLuc01 Sunday, March 25, 2018 2:53 PM
    Sunday, March 25, 2018 2:47 PM