Virtual Developer Workshop: Containerized Development with Docker
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.