# Moving and Sizing Pictureboxes

Monday Jun 23rd 2008 by Richard Newcombe
Share:

Cover a simple problem that often takes the longest time to solve because of the math required.

Often, when working with pictureboxes, you need to give users the ability to manipulate the size and position of the picturebox. In this article, you are going to look at two different situations that may arise:

• The image is larger than the form, and you need to be able to scroll the image around.
• Resize and move a smaller image over a larger one.

You are going to cover each problem individually The project download will contain both methods.

### Problem 1: Image is Larger than the Form or Screen

This is a very real problem faced by any number of applications, especially image editing/viewing software. You need to add the ability to view a small section of the image and have a scroller to move around it. Your first task is to create your form and add two Pictureboxes, a Horizontal and a Vertical scroller, to it. Your goal here is to use one picturebox as a simple holder and the second as your image object.

I've used the Anchor properties of .NET to lock the location and sizing of the Scrollers and the holder picturebox; this allows you to concentrate more on the values of the controls and not so much the location and size. This is turn reduces the amount of code needed.

The first thing you do is set the Parent for your image object to the holder.

`   PictureBox2.Parent = PictureBox1`

Now, you look at what happens when the form is resized. You create a sub to handle the values required for your Scrollers in relation to the size difference between your image and your form, the image holder in this case. All the values are derived from the difference of the two picturebox sizes.

You create a sub, 'ScrollAdjust', to handle these calculations that you can call as and when required.

```Private Sub ScrollAdjust()
'used for resizing the parent form & holder !!
With PictureBox2
If .Width < PictureBox1.Width Then
.Left = (PictureBox1.Width - .Width) / 2
HScrollBar1.Enabled = False
Else
If .Left > 0 Then .Left = 0
HScrollBar1.Minimum = 0
HScrollBar1.Maximum = .Width - PictureBox1.Width
HScrollBar1.SmallChange = 1
HScrollBar1.LargeChange = 10
HScrollBar1.Enabled = True
End If
If .Height < PictureBox1.Height Then
.Top = (PictureBox1.Height - .Height) / 2
VScrollBar1.Enabled = False
Else
If .Top > 0 Then .Top = 0
VScrollBar1.Minimum = 0
VScrollBar1.Maximum = .Height - PictureBox1.Height
VScrollBar1.SmallChange = 1
VScrollBar1.LargeChange = 10
VScrollBar1.Enabled = True
End If
End With
End Sub
```

A first look at this sub may intimidate you; however, it's very simple. The basics are, if the image is smaller than the holder, place it in the centre and disable the scroller; if the image is larger than the holder, make sure there is no border, and set the scroller maximum to the size difference. You do this individually for the width and the height of the image.

Next, you look at what happens when you want to move the image with the Scrollers. Because all of the critical calculations have been done, this is the easy part. All that is needed is to reposition the image.

```Private Sub VScrollBar1_Scroll(ByVal sender As System.Object, _
ByVal e As System.Windows.Forms.ScrollEventArgs)_
Handles VScrollBar1.Scroll
PictureBox2.Top = -VScrollBar1.Value

End Sub

Private Sub HScrollBar1_Scroll(ByVal sender As System.Object, _
ByVal e As System.Windows.Forms.ScrollEventArgs)_
Handles HScrollBar1.Scroll
PictureBox2.Left = -HScrollBar1.Value

End Sub
```

One big question I've been asked several times is why do you use the Negative value and not a positive value. That's simple; the top left corner of a control is always 0,0 (X,Y) with the positive moving down and to the right. So, if you use the positive you move the top left corner of the image down and to the right, pushing your bottom right corner further away from view. However, if you use the negative and push the top left corner out of view, you get closer to the bottom right corner. Once you've moved it by the total calculated difference, the bottom right corner should be in full view.

In theory, this is true; in practice, you need to look at a few other items, namely docked objects. If there are any docked objects in the holder, you need to compensate for them. There are many variants, and to display the code for each will take time; however, a brief description should help you if need be.

The width or height of the docked object needs to be added to the difference in size. This is critical because the docked object will lay over the image and hide portions of it. Handling the movement of the image also requires some special thought.

Docked object on the top or left: You need to offset the top or left of the image to slip past the docked object. Something like the following code will be needed.

`   PictureBox2.Top = -VScrollBar1.Value + DockedObject.height`

Docked object on the bottom or right: Here, you are a little more fortunate. By adding the size to your calculated difference, the normal scrolling will pull the bottom right corner past the holder's corner and just up to where the docked object stands. There is no need to adjust anything else here.

One very important thing to remember here is that any docked object will affect only the visible height or width of the holder, but not both. Also, multiple docked objects must be taken into consideration.

Okay, moving on, you also need to allow the user to click on the image and move it. This is not as critical but is always a nice feature to include. Because the left click is generally used to start or move a selection, you going to use the Scroll click (or middle button click) to move the complete image.

The first step is to detect this mouse click, when it's pressed and when it's released. You use the 'Mousedown' and 'Mouseup' events. You set a Boolean value to represent this state, and record the starting location of the click.

```Private StartCord As Drawing.Point
Private MoveMain As Boolean

Private Sub PictureBox2_MouseDown(ByVal sender As Object, _
ByVal e As System.Windows.Forms.MouseEventArgs)_
Handles PictureBox2.MouseDown
If e.Button = Windows.Forms.MouseButtons.Middle Then
MoveMain = True
StartCord = e.Location
End If
End Sub

Private Sub PictureBox2_MouseUp(ByVal sender As Object, _
ByVal e As System.Windows.Forms.MouseEventArgs)_
Handles PictureBox2.MouseUp
MoveMain = False
End Sub
```

Thereafter, in the 'Mousemove' event you check the state of the Boolean variable and adjust the location of the image according to the difference between the current position and start position.

```Private Sub PictureBox2_MouseMove(ByVal sender As Object, _
ByVal e As System.Windows.Forms.MouseEventArgs)_
Handles PictureBox2.MouseMove
If MoveMain Then
If VScrollBar1.Enabled Then
newCord.Y = PictureBox2.Top - (StartCord.Y - e.Location.Y)
If newCord.Y > 0 Then newCord.Y = 0
If newCord.Y < -VScrollBar1.Maximum Then newCord.Y = _
-VScrollBar1.Maximum
PictureBox2.Top = newCord.Y
VScrollBar1.Value = -newCord.Y
End If
If HScrollBar1.Enabled Then
newCord.X = PictureBox2.Left - (StartCord.X - e.Location.X)
If newCord.X > 0 Then newCord.X = 0
If newCord.X < -HScrollBar1.Maximum Then _
newCord.X = -HScrollBar1.Maximum
PictureBox2.Left = newCord.X
HScrollBar1.Value = -newCord.X
End If
End If
End Sub
```

Having done all of this, you should have a project now that will allow any image loaded into Picturebox2 to be viewed inside a sizable form and scrolled to any corner.

### Problem 2: Sizing and Moving One Image on Top of Another

Now, you are going to look at what needs be done to allow a smaller image to be placed over a larger image. This situation arises in many forms and ways. For the reason of supplying the code required to enable this, I will be working with a picturebox within a picturebox. Firstly, this allows you to evaluate only the code required to move and resize the object, without the Stretch and zoom code there to complicate it. Secondly, with the Picturebox taking care of zooming and stretching the image, you don't need to complicate the project with APIs, Buffering and Graphics objects.

This example is taken from a real program requirement, and was written when a work colleague asked me to assist with code to allow a user to place a company logo on top of an image. The rest of the requirements are not important to this article, but some included the ability to reproduce the final selection, and to alter the inserted image but leave it in the same location.

Okay, you are going to place this smaller image on top of the image you have in the previous example. So, in the project you now add a new picturebox to the form. You also set it as a child object of the picturebox.

```   PictureBox3.Parent = PictureBox2
PictureBox3.SizeMode = PictureBoxSizeMode.StretchImage
```

Setting the 'Sizemode' to Stretchimage allows the picturebox control to manipulate the image to fit the selected size. Hence, no code is required to zoom and stretch the image.

Now, where do you start with the smaller image? You start with location. You want to be able to move the image to wherever it is required. This is done with a left click on the image and moving the mouse.

```Private Sub PictureBox3_MouseDown(ByVal sender As Object, _
ByVal e As System.Windows.Forms.MouseEventArgs)_
Handles PictureBox3.MouseDown
If e.Button = Windows.Forms.MouseButtons.Left Then
StartCord = e.Location
MovePic = True
End If
End Sub

Private Sub PictureBox3_MouseMove(ByVal sender As Object, _
ByVal e As System.Windows.Forms.MouseEventArgs)_
Handles PictureBox3.MouseMove
' Mouse move inside Image Region... - NB. Child Picturebox
If e.Button = Windows.Forms.MouseButtons.Left Then
If MovePic Then
PictureBox3.Top = PictureBox3.Top + _
(e.Location.Y - StartCord.Y)
PictureBox3.Left = PictureBox3.Left + _
(e.Location.X - StartCord.X)
End If
End If
End Sub

Private Sub PictureBox3_MouseUp(ByVal sender As Object, _
ByVal e As System.Windows.Forms.MouseEventArgs)_
Handles PictureBox3.MouseUp
MovePic = False
End Sub
```

Wow, that's easy, you may say. Yes, it is that easy to move any object on a form. Although there are a few things that need to known, 'e.Location' holds the location of the mouse pointer on Picturebox3. As the picturebox moves, so does the 'Location' of the mouse on top of it. So now, if you look at the code a little closer with this information, you can see that what you doing is moving the picturebox so that your pointer is always on the same spot. This is achieved by adding the difference of the original position and the current position to the location of the object. In other words, if the mouse moved 3 pixels to the left, move the object 3 pixels to the left.

With the 'mousedown' event, you set a Boolean Movepic variable so that you can use this state in the 'mousemove' event to decide what action to take.

Note: This code is specific to move an object on an object; alternate code is used to move a rectangular region on an object.

Now, you need to start with the code to size this image. The first thing you need to do is detect the edges of the image and change the pointer to show that you are ready to size.

```Private wEdge As Boolean
Private eEdge As Boolean
Private nEdge As Boolean
Private sEdge As Boolean
Private Sizing As Boolean
Private Const EdgeSize As Integer = 6
Private SizePic As Boolean

Private Sub PictureBox3_MouseMove(ByVal sender As Object, _
ByVal e As System.Windows.Forms.MouseEventArgs)_
Handles PictureBox3.MouseMove
' Mouse move inside Image Region... - NB. Child Picturebox
If e.Button = Windows.Forms.MouseButtons.None Then
If e.Location.X < EdgeSize And e.Location.X > 0 Then
wEdge = True
Else
wEdge = False
End If
If e.Location.X > PictureBox3.Size.Width - EdgeSize And_
e.Location.X < PictureBox3.Size.Width Then
eEdge = True
Else
eEdge = False
End If
If e.Location.Y < EdgeSize And e.Location.Y > 0 Then
nEdge = True
Else
nEdge = False
End If
If e.Location.Y > PictureBox3.Size.Height - EdgeSize And_
e.Location.Y < PictureBox3.Size.Height Then
sEdge = True
Else
sEdge = False
End If
Sizing = True
ElseIf e.Button = Windows.Forms.MouseButtons.Left Then
If MovePic Then
PictureBox3.Top = PictureBox3.Top + _
(e.Location.Y - StartCord.Y)
PictureBox3.Left = PictureBox3.Left + _
(e.Location.X - StartCord.X)
End If
End If

' The code following works when used with a child Picturebox...
If (nEdge Or sEdge) And Not (wEdge Or eEdge) Then
PictureBox3.Cursor = Cursors.SizeNS
ElseIf (wEdge Or eEdge) And Not (nEdge Or sEdge) Then
PictureBox3.Cursor = Cursors.SizeWE
ElseIf (nEdge And eEdge) Or (sEdge And wEdge) Then
PictureBox3.Cursor = Cursors.SizeNESW
ElseIf (nEdge And wEdge) Or (sEdge And eEdge) Then
PictureBox3.Cursor = Cursors.SizeNWSE
Else
PictureBox3.Cursor = Cursors.Default
Sizing = False
End If

End Sub
```

With the additional code in the 'mousemove' event, you look for the edge (with an adjustable size) and show the appropriate cursor. You also set a Boolean variable Sizing when at the edge. This gives you the ability to use this state in the 'mousedown' event.

```Private Sub PictureBox3_MouseDown(ByVal sender As Object, _
ByVal e As System.Windows.Forms.MouseEventArgs)_
Handles PictureBox3.MouseDown
' Click on Sizable Image Region - NB. Child picturebox
If e.Button = Windows.Forms.MouseButtons.Left Then
OldCord = e.Location
StartCord = e.Location
If Sizing Then
SizePic = True
Else
MovePic = True
End If
End If
End Sub

Private Sub PictureBox3_MouseUp(ByVal sender As Object, _
ByVal e As System.Windows.Forms.MouseEventArgs)_
Handles PictureBox3.MouseUp
' Release Click in Sizable Image Region - NB. Child picturebox
SizePic = False
MovePic = False
End Sub
```

With the sizing variable, you now can check whether the mouse click is to size or move the image, and you set the relevant variables for this. All that is left is to code is the sizing.

```Private Sub PictureBox3_MouseMove(ByVal sender As Object, _
ByVal e As System.Windows.Forms.MouseEventArgs)_
Handles PictureBox3.MouseMove
' Mouse move inside Image Region... - NB. Child Picturebox
If e.Button = Windows.Forms.MouseButtons.None Then
If e.Location.X < EdgeSize And e.Location.X > 0 Then
wEdge = True
Else
wEdge = False
End If
If e.Location.X > PictureBox3.Size.Width - EdgeSize And_
e.Location.X < PictureBox3.Size.Width Then
eEdge = True
Else
eEdge = False
End If
If e.Location.Y < EdgeSize And e.Location.Y > 0 Then
nEdge = True
Else
nEdge = False
End If
If e.Location.Y > PictureBox3.Size.Height - EdgeSize And_
e.Location.Y < PictureBox3.Size.Height Then
sEdge = True
Else
sEdge = False
End If
Sizing = True
ElseIf e.Button = Windows.Forms.MouseButtons.Left Then
If MovePic Then
PictureBox3.Top = PictureBox3.Top + _
(e.Location.Y - StartCord.Y)
PictureBox3.Left = PictureBox3.Left + _
(e.Location.X - StartCord.X)
End If
' The code following works when used with a child
' Picturebox...
' NB. Alternate code will apply if working on a rect region
' selection.....
If SizePic Then
Rect.Top = PictureBox3.Top
Rect.Height = PictureBox3.Height
Rect.Left = PictureBox3.Left
Rect.Width = PictureBox3.Width
If eEdge Then
Rect.Width = e.Location.X
End If
If sEdge Then
Rect.Height = e.Location.Y
End If
If wEdge Then
Rect.Left = Rect.Left - (StartCord.X - e.Location.X)
Rect.Width = Rect.Width + (StartCord.X - e.Location.X)
End If
If nEdge Then
Rect.Top = Rect.Top - (StartCord.Y - e.Location.Y)
Rect.Height = Rect.Height + (StartCord.Y - e.Location.Y)
End If
If Rect.Height < 0 Then
Rect.Top = Rect.Top + Rect.Height
Rect.Height = Math.Abs(Rect.Height)
nEdge = Not nEdge
sEdge = Not sEdge
StartCord.Y = 0
End If
If Rect.Width < 0 Then
Rect.Left = Rect.Left + Rect.Width
Rect.Width = Math.Abs(Rect.Width)
eEdge = Not eEdge
wEdge = Not wEdge
StartCord.X = 0
End If
PictureBox3.Top = Rect.Top
PictureBox3.Height = Rect.Height
PictureBox3.Left = Rect.Left
PictureBox3.Width = Rect.Width
End If
End If
If (nEdge Or sEdge) And Not (wEdge Or eEdge) Then
PictureBox3.Cursor = Cursors.SizeNS
ElseIf (wEdge Or eEdge) And Not (nEdge Or sEdge) Then
PictureBox3.Cursor = Cursors.SizeWE
ElseIf (nEdge And eEdge) Or (sEdge And wEdge) Then
PictureBox3.Cursor = Cursors.SizeNESW
ElseIf (nEdge And wEdge) Or (sEdge And eEdge) Then
PictureBox3.Cursor = Cursors.SizeNWSE
Else
PictureBox3.Cursor = Cursors.Default
Sizing = False
End If

OldCord = e.Location
End Sub
```

There's a lot happening in the sizing code. The first thing that you do is check which edge you are sizing, allowing for corners where you size two edges.

Thereafter, you check to see whether you crossed over the opposite edge. Because a picture box with a width of -1 will always default to zero, you use a rectangle type to temporarily store your values. If you have crossed over the opposite edge, you flip the negative size and the variables, and then, where needed, the cursor.

If all was done correctly, you should have a project with perfect image object move and size code. The attached project shows a working example of both methods been used on a single form.

### In Conclusion

Hannes du Preez wrote a beautiful series of articles about image editing. This is a perfect addin to that project, available here on Part 4 .

Share:
Home
Mobile Site | Full Site