VB.Net make draggable controls not go outside the form - vb.net

I have a custom control that is draggable using the code below, but the problem is that i can move the control outside the form.
Private Sub ObjCan_MouseMove(sender As Object, e As MouseEventArgs) Handles Me.MouseMove
If e.Button = Windows.Forms.MouseButtons.Left Then
Me.Location = New Point(FormGame.PointToClient(MousePosition).X - 16, FormGame.PointToClient(MousePosition).Y - 16)
End If
End Sub

Set Cursor.Clip to limit mouse movement:
Gets or sets the bounds that represent the clipping rectangle for the
cursor. A clipped cursor is allowed to move only within its clipping
rectangle.
Here's a quick example with a Label. Note that if you moved the Label into a different container, like a Panel, the code would still work and the Label would be confined to the Panel bounds instead:
Public Class Form1
Private PrevClip As Rectangle
Private Sub Label1_MouseDown(sender As Object, e As MouseEventArgs) Handles Label1.MouseDown
PrevClip = Cursor.Clip
Dim ctl As Control = DirectCast(sender, Control)
Dim ctlContainer As Control = ctl.Parent
Cursor.Clip = ctlContainer.RectangleToScreen(New Rectangle(0, 0, ctlContainer.ClientSize.Width - ctl.Width, ctlContainer.ClientSize.Height - ctl.Height))
End Sub
Private Sub Label1_MouseMove(sender As Object, e As MouseEventArgs) Handles Label1.MouseMove
If e.Button = MouseButtons.Left Then
Dim ctl As Control = DirectCast(sender, Control)
Dim ctlContainer As Control = ctl.Parent
ctl.Location = ctlContainer.PointToClient(Cursor.Position)
End If
End Sub
Private Sub Label1_MouseUp(sender As Object, e As MouseEventArgs) Handles Label1.MouseUp
Cursor.Clip = PrevClip
End Sub
End Class

Related

How to autoscroll panel or picturebox in MouseMove event in VB:NET

I'm trying to autoscroll panel with an image using mousemove event simulating a dynamic zoom.
I found this example Pan/scroll an image in VB.NET and this Scroll panel based on mouse position in VB.NET but I realized that the user have to click on the image to drag it, so I tried to modify the code but doesn't work
This is what I tried:
Private m_PanStartPoint As New Point
Private Sub PictureBox2_MouseMove(sender As Object, e As MouseEventArgs) Handles PictureBox2.MouseMove
Dim DeltaX As Integer = (m_PanStartPoint.X - e.X)
Dim DeltaY As Integer = (m_PanStartPoint.Y - e.Y)
Panel1.AutoScrollPosition = New Point((DeltaX - Panel1.AutoScrollPosition.X), (DeltaY - Panel1.AutoScrollPosition.Y))
End Sub
Private Sub PictureBox2_MouseEnter(sender As Object, e As EventArgs) Handles PictureBox2.MouseEnter
PictureBox2.SizeMode = PictureBoxSizeMode.AutoSize
m_PanStartPoint = New Point(MousePosition)
End Sub
Private Sub PictureBox2_MouseLeave(sender As Object, e As EventArgs) Handles PictureBox2.MouseLeave
PictureBox2.SizeMode = PictureBoxSizeMode.StretchImage
End Sub
I also tried adding the event MouseHover:
Private Sub PictureBox2_MouseHover(sender As Object, e As EventArgs) Handles PictureBox2.MouseHover
m_PanStartPoint = New Point(MousePosition)
End Sub
if there is a way to do it without a panel, it would be better.
'The VB/XAML code below implements left mouse button click+hold scrolling and also works with touch screens. When using this code, put your frame/grid/image within a scrollviewer as shown below:
'XAML
<ScrollViewer x:Name="ScrollViewerObject" HorizontalScrollBarVisibility="Disabled" VerticalScrollBarVisibility="Hidden" ScrollViewer.CanContentScroll="False" PreviewMouseDown="Part_ScrollViewer_PreviewMouseDown" PreviewMouseMove="Part_ScrollViewer_PreviewMouseMove">
<Frame x:Name="PartViewer" NavigationUIVisibility="Hidden"/>
</ScrollViewer>
'VB
Dim LastScrollPos As Double = 0
Dim MouseStartPos AS Double = 0
Private Sub ScrollViewerObject_PreviewMouseDown(sender As Object, e As MouseButtonEventArgs)
Dim position As Point = Mouse.GetPosition(ScrollViewerObject)
ScrollViewerObject.UpdateLayout()
LastScrollPos = ScrollViewerObject.ContentVerticalOffset
MouseStartPos = position.Y
End Sub
Private Sub ScrollViewerObject_PreviewMouseMove(sender As Object, e As MouseEventArgs)
If Mouse.LeftButton = MouseButtonState.Pressed Then
Dim position As Point = Mouse.GetPosition(ScrollViewerObject)
ScrollViewerObject.ScrollToVerticalOffset(LastScrollPos + (position.Y - MouseStartPos))
End If
End Sub

Remove Or Delete the Rectangle drawn on the PictureBox

I am currently solving a bug that will remove the created rectangle on the PictureBox. The problem is that when I click an Item on the PictureBox and Resize the windows form, the rectangle does not move on with the item selected. This is the code creating the rectangle:
Private Sub paintRectangle(pictBox As System.Windows.Forms.PictureBox, pic As Image)
If pic Is Nothing Then Exit Sub
pictBox.Image = pic
If m_rect_x = -1 And m_rect_y = -1 Then
Return
End If
Dim graphic As System.Drawing.Graphics
Dim redselpen As System.Drawing.Pen
Dim yNegative As Integer = 3
redselpen = New System.Drawing.Pen(Color.Blue)
redselpen.DashStyle = Drawing2D.DashStyle.DashDot
If pictBox.Image IsNot Nothing Then
graphic = System.Drawing.Graphics.FromImage(pictBox.Image)
graphic.DrawRectangle(redselpen, m_rect_x, m_rect_y - yNegative, SystemConfig.iRectWidth, SystemConfig.iRectHeight + 2)
pictBox.Image = pictBox.Image
End If
End Sub
After Resizing the Form, I want to remove the create a rectangle on the PictureBox.
I tried this solution but the Rectangle is still in the PictureBox.
How to remove all the drawn rectangles on the picture box? (Not on the image)
But it does not work, the rectangle is still in the picturebox.
Here's a simple example showing the Paint() event of a PictureBox being used to draw a rectangle that can be moved and turned on/off:
Public Class Form1
Private yNegative As Integer = 3
Private pt As New Nullable(Of Point)
Private drawRectangle As Boolean = False
Private Sub PictureBox1_Paint(sender As Object, e As PaintEventArgs) Handles PictureBox1.Paint
If drawRectangle AndAlso pt.HasValue Then
Using redselpen As New System.Drawing.Pen(Color.Blue)
redselpen.DashStyle = Drawing2D.DashStyle.DashDot
e.Graphics.DrawRectangle(redselpen, pt.Value.X, pt.Value.Y - yNegative, SystemConfig.iRectWidth, SystemConfig.iRectHeight + 2)
End Using
End If
End Sub
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
pt = New Point(25, 25)
drawRectangle = True
PictureBox1.Invalidate()
End Sub
Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
drawRectangle = Not drawRectangle ' toggle the rectangle on/off
PictureBox1.Invalidate()
End Sub
Private Sub Button3_Click(sender As Object, e As EventArgs) Handles Button3.Click
pt = New Point(150, 25)
drawRectangle = True
PictureBox1.Invalidate()
End Sub
End Class

PictureBox2.Image = PictureBox1.Image seems to be linking the boxes instead of copying the image over?

The Problem
I have a simple form with 2 PictureBoxes
I allow the user to draw on PictureBox1
When I click a Button on the form I want to capture the image in PictureBox1 and store it in PictureBox2
The issue is that if I add the line:
PictureBox2.Image = PictureBox1.Image
Any updates to PictureBox1 are immediately reflected in PictureBox2 ?!?
I just want to capture the image in PictureBox1 at that moment in time so that I can use it to 'Undo'
Tech
It's a Windows Forms App in Visual Basic, .Net 4.7.2 using Visual Studio 2019 Preview
Code
Public Class Form1
Dim drawMouseDown = False ' Set initial mouse state to not clicked
Dim drawMyBrush As New Pen(Brushes.White, 20) 'Set up the Brush
Public drawCanvas As New Bitmap(245, 352) 'Set up Bitmap Canvas
Private Sub btn_Color_Yellow_Click(sender As Object, e As EventArgs) Handles btn_Color_Yellow.Click
drawMyBrush.Brush = Brushes.Yellow
drawMyBrush.Width = 20
End Sub
Private Sub PictureBox1_MouseDown(sender As Object, e As MouseEventArgs) Handles PictureBox1.MouseDown
drawMouseDown = True
End Sub
Private Sub PictureBox1_MouseUp(sender As Object, e As MouseEventArgs) Handles PictureBox1.MouseUp
drawMouseDown = False
End Sub
Private Sub PictureBox1_MouseMove(sender As Object, e As MouseEventArgs) Handles PictureBox1.MouseMove
Dim g As Graphics = Graphics.FromImage(drawCanvas)
Static coord As New Point
If drawMouseDown Then
g.SmoothingMode = Drawing2D.SmoothingMode.HighQuality
drawMyBrush.StartCap = Drawing2D.LineCap.Round
drawMyBrush.EndCap = Drawing2D.LineCap.Round
g.DrawLine(drawMyBrush, coord.X, coord.Y, e.X, e.Y)
g.Dispose()
PictureBox1.Image = drawCanvas
Me.Refresh()
End If
coord = e.Location
End Sub
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
PictureBox2.Image = PictureBox1.Image 'Why does this not just update the PicBox2 image once?!? (or only when the Button is clicked)
End Sub
End Class
Expectation
When Button1 is clicked I expect PictureBox2 to contain the PictureBox1 image, when I continue to draw on PictureBox1 I do NOT expect it to keep updating PictureBox2 as the user is drawing on the other!
As you suspect, PictureBox2.Image = PictureBox1.Image makes the former a reference to the latter.
What you can do instead is clone the image:
PictureBox2.Image = DirectCast(PictureBox1.Image.Clone(), Image)
Because you are referencing the Image property of PictureBox2 to PictureBox1.Image. So when they both point to the same reference, any changes to either of the PictureBox's image property, will affect the other's.
In order to avoid his, make a new instance of Bitmap object based on the PictureBox1.Image and set it to PictureBox2.Image:
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
PictureBox2.Image = New Bitmap(PictureBox1.Image)
End Sub

How to move a picturebox within a panel

I can move a picturebox from a Form to a panel as follows (both PictureBox1 and Panel1 are on the same Form control). But once it is in panel1, PictureBox1 doesn't move with MouseMove event. My intention is, once the picturebox entered the panel area, I want to move it freely (MouseMove) only within the Panel area. Can anyone help me to achieve this?
The code is this:
Dim locate As Point
Private Sub PictureBox1_MouseDown(ByVal sender As Object, ByVal e As MouseEventArgs) Handles PictureBox1.MouseDown
locate = New Point(-e.X, -e.Y)
End Sub
Private Sub PictureBox1_MouseMove(ByVal sender As Object, ByVal e As MouseEventArgs) Handles PictureBox1.MouseMove
If e.Button = Windows.Forms.MouseButtons.Left Then
Dim MoveTo As Point = Me.PointToClient(MousePosition)
MoveTo.locate(locate.X, locate.Y)
If PictureBox1.Location.X < Panel1.Location.X Then
PictureBox1.Location = MoveTo
End If
End If
End Sub

border less form gets automatically resized during runtime in vb .net

I've created a small borderless form using vb .net. The form contains three square buttons. The size of the form is (93, 31). All good during the design of the form, but when I run the program the size of the form gets increased to somewhat like (98,34). I even switched between true and false for the autosize property of the form to check if it was the cause of the problem but that dint help.
How do I stop the form from resizing?
EDIT:
I made the form borderless by setting the form's FormBorderStyle property to None
Here's the code
Public Class OSD_Dialog
Dim drag As Boolean
Dim mousex As Integer
Dim mousey As Integer
' The folllowing three subs are helpfull in making the form dragable
Private Sub Form1_MouseDown(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles Me.MouseDown
drag = True
mousex = Windows.Forms.Cursor.Position.X - Me.Left
mousey = Windows.Forms.Cursor.Position.Y - Me.Top
End Sub
Private Sub Form1_MouseMove(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles Me.MouseMove
If drag Then
Me.Top = Windows.Forms.Cursor.Position.Y - mousey
Me.Left = Windows.Forms.Cursor.Position.X - mousex
End If
End Sub
Private Sub Form1_MouseUp(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles Me.MouseUp
drag = False
End Sub
'The following sub is helpful in creating an outline on the border of the form
Protected Overrides Sub OnPaintBackground(ByVal e As PaintEventArgs)
MyBase.OnPaintBackground(e)
Dim rect As New Rectangle(0, 0, Me.ClientSize.Width - 1, Me.ClientSize.Height - 1)
e.Graphics.DrawRectangle(Pens.White, rect)
End Sub
Private Sub OSD_Dialog_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Me.TopMost = True
Me.SetStyle(ControlStyles.SupportsTransparentBackColor, True)
Me.BackColor = Color.Red
TransparencyKey = BackColor
End Sub
Add this to your Form_Load event:
Me.Size = New Size(93, 31)
Also ensure you have set AutoScaleMode to 'None' in design time