Picturebox / Panel tearing when drag vb.net - vb.net

I'm trying to make VB.net program and UI is like normal desktop. I have images in picture
boxes as desktop shortcuts. So user can drag them around in form. Btw im not skilled just started
to do things like this.
I can move picture boxes with mouse events its fine But pictures in pictureboxes are tearing when dragging. i have a big background picture, i guess this is the problem but i need help to get rid of tearing. heres code thx.
i also tryed as a panel and get same result.
Edit : pictures about dragging is png , 50x50 , transparent BG.
Public Class testform
Dim drag As Boolean
Dim mousex, mousey As Integer
Private Sub testform_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Me.BackgroundImage = My.Resources.worldmap 'approx 1.03mb Picture size
End Sub
Private Sub dragbox_MouseDown(sender As Object, e As MouseEventArgs) Handles dragbox.MouseDown
If e.Button = Windows.Forms.MouseButtons.Left Then
drag = True
mousex = Windows.Forms.Cursor.Position.X - dragbox.Left
mousey = Windows.Forms.Cursor.Position.Y - dragbox.Top
Else
End If
End Sub
Private Sub dragbox_MouseMove(sender As Object, e As MouseEventArgs) Handles dragbox.MouseMove
If drag = True Then
dragbox.Left = Windows.Forms.Cursor.Position.X - mousex
dragbox.Top = Windows.Forms.Cursor.Position.Y - mousey
End If
End Sub
Private Sub dragbox_MouseLeave(sender As Object, e As EventArgs) Handles dragbox.MouseLeave
drag = False
End Sub
End Class

You need to make the picture form double buffered. That means that it will no longer tear as it will first completely make sure it's all in place before showing the next frame.

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

If something gets out of the panel in the top side then make it go to (0, 0) position, if in the botton side then (0, Panel Height Size)

So basically I've been trying to program a custom ScrollBar for my WinForm written in VB.NET and I don't seem to make it have a limit of the movement.
Code without limit tries:
Public Class GoldSrcScrollBar
Dim drag As Boolean
Dim mousey As Integer
Private Sub GoldSrcScrollBtn1_MouseDown(sender As Object, e As MouseEventArgs) Handles GoldSrcScrollBtn1.MouseDown
drag = True
mousey = Cursor.Position.Y - GoldSrcScrollBtn1.Top
End Sub
Private Sub GoldSrcScrollBtn1_MouseUp(sender As Object, e As MouseEventArgs) Handles GoldSrcScrollBtn1.MouseUp
drag = False
End Sub
Private Sub GoldSrcScrollBtn1_MouseMove(sender As Object, e As MouseEventArgs) Handles GoldSrcScrollBtn1.MouseMove
If drag Then
GoldSrcScrollBtn1.Top = Cursor.Position.Y - mousey
End If
End Sub
I have no idea how to make it have a limit
Slider = GoldSrcScrollBtn1
ScrollBar Background = GoldSrcScrollBarBg1
Without limit it works like this:
As you can see, it gets out of the Panel (GoldSrcScrollBarBg1).
Could someone help me please? Thanks :)

Resize Bordless Form is Glitchy

My code to resize my form from the right hand side works, but is really glitchy or has a lot of lag. All my images blur and my drawn rectangles flicker while I'm resizing. Everything is normal however once mouseup.
I put the formborderstyle from borderless to sizable and the form resizes normally.
Hoping someone might be able to point out what is wrong with my code.
Dim myresize As Boolean = False
Dim cursorx As Integer
Dim cursory As Integer
Private Sub TableLayoutPanel1_MouseDown(sender As Object, e As MouseEventArgs) Handles TableLayoutPanel1.MouseDown
If e.Location.X > Me.Width - 7 And e.Location.Y > 11 And e.Location.Y < Me.Height - 10 Then
myresize = True
cursorx = Windows.Forms.Cursor.Position.X - Me.Width
cursory = Windows.Forms.Cursor.Position.Y - Me.Height
End If
End Sub
Private Sub TableLayoutPanel1_MouseMove(sender As Object, e As MouseEventArgs) Handles TableLayoutPanel1.MouseMove
If myresize = True Then
Me.Width = Windows.Forms.Cursor.Position.X - cursorx
End If
End Sub
Private Sub TableLayoutPanel1_MouseUp(sender As Object, e As MouseEventArgs) Handles TableLayoutPanel1.MouseUp
myresize = False
End Sub
For the flickering, the form does not pass the DoubleBuffered property to its child controls, such as your TableLayoutPanel. Instead try adding a new class to your project that will doubleBuffer the tableLayoutPanel.
Public Class DoubleBufferedTableLayoutPanel
Inherits TableLayoutPanel
Public Sub New()
Me.DoubleBuffered = True
End Sub
End Class
Build your project and the new version of the TableLayoutPanel will be in your toolbox as DoubleBufferedTableLayoutPanel. From there just use it as you would the TableLayoutPanel in your code.

Graphics.DrawRectangle not working in control events

First of all thank you for taking the time out of your busy schedule to assist me.
I am developing a project (Win Application) with a Form and 3 textboxes (TextBox1, TextBox2 and TextBox3).
I need draw a rectangle around the textbox when focused this.
The code is:
Private Sub TextBox123_Enter(sender As Object, e As System.EventArgs) Handles TextBox1.Enter, TextBox2.Enter, TextBox3.Enter
Using g As Graphics = Me.CreateGraphics
Dim r As Rectangle = sender.Bounds
r.Inflate(4, 4)
g.DrawRectangle(Pens.Blue, r)
End Using
End Sub
The problem is the following:
The first time the textbox1 gains focus rectangle is not drawn.
The first time the textbox2 gains focus rectangle is not drawn.
Why not the rectangle is drawn when the first two events enter are fired?
Drawing with CreateGraphics is almost always not the correct approach. If you notice also, when you move from one box to another, the old rectangle is not being erased. You need to use the Form_Paint event to get it to work right. Or...perhaps simpler would be to create a UserControls which is 1-2 pixels larger than a child TextBox and set the backcolor of the UserControl canvas, draw your rectangle when the control gets the focus.
For form paint:
Public Class Form1
Private HotControl As Control
If you are only going to do TextBoxes, you can declare it As TextBox. This way it allows you to do the same for other control types. Set/clear the tracker:
Private Sub TextBox3_Enter(sender As Object, e As EventArgs) Handles TextBox3.Enter,
TextBox2.Enter, TextBox1.Enter
HotControl = CType(sender, TextBox)
Me.Invalidate()
End Sub
Private Sub TextBox1_Leave(sender As Object, e As EventArgs) Handles TextBox1.Leave,
TextBox2.Leave, TextBox3.Leave
HotControl = Nothing
Me.Invalidate()
End Sub
The Me.Invalidate tells the form to redraw itself, which happens in Paint:
Private Sub Form1_Paint(sender As Object, e As PaintEventArgs) Handles Me.Paint
If HotControl IsNot Nothing Then
Dim r As Rectangle = HotControl.Bounds
r.Inflate(4, 4)
e.Graphics.DrawRectangle(Pens.Blue, r)
End If
End Sub
You should also turn on Option Strict.
Try this in the click event handler
Private Sub TextBox1_Click(sender As Object, e As EventArgs) Handles TextBox1.Click
Using g As Graphics = Me.CreateGraphics()
Dim rectangle As New Rectangle(TextBox1.Location.X - 1, _
TextBox1.Location.Y - 1, _
TextBox1.Size.Width + 1, _
TextBox1.Size.Height + 1)
g.DrawRectangle(Pens.Blue, rectangle)
End Using
End Sub

Dynamically change pen color & paint when clicked

The Program
I'm playing around and learning about graphics using visual basic (coming from C++). I've made a program and I want to do two things: paint when the left mouse button is pressed, and stop when released, and also I want to be able to change the pen color using a colordialog. After hours of frustration, I've yet to combat these two problems.
The Code (Snippet)
Private obj As Graphics
Dim rect As Rectangle
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
obj = RichTextBox1.CreateGraphics
End Sub
Private Sub Form1_FormClosed(ByVal sender As System.Object, ByVal e As System.Windows.Forms.FormClosedEventArgs) Handles MyBase.FormClosed
obj.Dispose()
End Sub
Private Sub RichTextBox1_MouseMove(ByVal sender As System.Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles RichTextBox1.MouseMove
With rect
.X = e.X
.Y = e.Y
.Width = TrackBar1.Value
.Height = TrackBar1.Value
End With
If ToolStripButton1.Checked = True Then
obj.DrawEllipse(Pens.Black, rect)
ElseIf ToolStripButton2.Checked = True Then
obj.DrawRectangle(Pens.Black, rect)
End If
ToolStripStatusLabel2.Text = (e.X & ", " & e.Y)
End Sub
Past Attempts (and frustrations)
My idea originally was to do this:
Dim myPen = New Pen(ButtonWithDC1.BackColor)
But doing so gave me an error message. I looked at Microsoft's documentation, but it wasn't useful for what I'm trying to do. I can create a pen just fine, but I'd like for the user to be able to change the color while the app is currently running.
GUI Layout
I don't have an attempt at my other problem (drawing while pressing the mouse down, not just by moving the mouse -- like a normal paint program), I don't even have a starting point for that solution. Thanks to everyone in advance.
Place a button (Button1) and picturebox (PictureBox1) on a form, also add a colordialog (ColorDialog1).
This code will allow you to draw on the picture box and choose the color using a color you select from the colordialog. The MouseDown event writes a flag that the mouse is down, and stores the last location. The MouseUp does similar. The MouseMove actually draws. Use a line and the last location.
Public Class Form1
Private myColor As Color = Color.Black
Private mouseIsDown As Boolean = False
Private previousLocation As System.Nullable(Of System.Drawing.Point) = Nothing
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
myColor = If(ColorDialog1.ShowDialog() = Windows.Forms.DialogResult.OK, ColorDialog1.Color, myColor)
End Sub
Private Sub PictureBox1_MouseDown(sender As Object, e As MouseEventArgs) Handles PictureBox1.MouseDown
mouseIsDown = True
previousLocation = e.Location
End Sub
Private Sub PictureBox1_MouseMove(sender As Object, e As MouseEventArgs) Handles PictureBox1.MouseMove
If mouseIsDown Then
If previousLocation IsNot Nothing Then
Using g As Graphics = Graphics.FromImage(PictureBox1.Image)
g.DrawLine(New Pen(myColor), previousLocation.Value, e.Location)
End Using
PictureBox1.Invalidate()
End If
previousLocation = e.Location
End If
End Sub
Private Sub PictureBox1_MouseUp(sender As Object, e As MouseEventArgs) Handles PictureBox1.MouseUp
mouseIsDown = False
previousLocation = Nothing
End Sub
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Me.PictureBox1.Image = New Bitmap(PictureBox1.Width, PictureBox1.Height)
End Sub
End Class
Your question is a bit more involved than you think, and SO is not keen on multiple questions per post (not in your nest interest either - someone might know A and not B so wont bother answering).
To draw on Mousemove when the mouse is down, you need to track when the mouse is down (question A):
Private _mouseDown As Boolean
Private _mouseLoc As Point
Private _mouseNewLoc As Point
sub Ctl_MouseDown(sender...
' ToDo: add logic to check which button....
_mouseDown = True
_mouseLoc = New Point(e.X, e.Y)
End Sub
sub Ctl_MouseUp(sender...
_mouseDown = False
End Sub
Then mousemove can be used to capture the current location
Sub Ctl_MouseMove(sender....
If _mouseDn Then
_mouseNewLoc = New Point(e.X, e.Y)
Ctl.invalidate ' call to paint
End If
End Sub
' selected color from dialog or whereever
Private myColor As Color
Sub Ctl_Paint(sender....
If _mouseDn Then
' Pen ctor is overloaded...(Question B)
Using p As New Pen(myColor)
e.Graphics.DrawLine(p, _mouseLoc, _mouseNewLoc)
' plus more....
End Using
End If
This only addresses the questions posed; the bigger issue you have is tracking what has already been drawn. This will draw a line only while the mouse is down, but for a polygon or shape, you have to add code to redraw those parts. Either a List of the points which make up a polygon, or maybe save what you have to a bitmap and add to it. Thats a bit outside the scope of the question and depends on app factors. You also need a Drawing start/stop or way to signal when to stop adding lines or ovals or whatever (ovals are sort of simple: one at a time, lines as part of a shape will take some work).
Either way all painting has to take place in the Paint event (or OnPaint) if you want to see the shape/drawing/image develop.