Do While Loop Going Until Button State Has Changed - vb.net

I want in a MouseDown event in a Winforms to be able to do some code until either a certain amount of seconds or MouseUp event has been fired off
I want something like this
Dim counter As Integer = 0
Do Until Button.Key IsNot MouseDown
counter += 1
If counter > 3
Exit Do Loop
End If
Application.DoEvents()
Loop
Right now I have it like
seconds = 0
m_mouseButtonIsNotDown = False
Do Until m_mouseButtonIsNotDown
If e.Button = Windows.Forms.MouseButtons.Left Then
seconds += 1
If seconds > 5 Then
m_mouseButtonIsNotDown = True
End If
End If
Application.DoEvents()
Loop
The desired behavior I am looking for is if they let go of the button within a certain amount of loops to handle the code that would be if it was just a simple mouseclick event. If the mousedown has been held for more then 3 or 5 seconds switch to drag and drop mode so they can move the desired row to another datagridview. I have tried to use Timer and StopWatch classes and it doesn't work how I would have expected it too. It doesn't work if I have a mouseclick event and the mousedown event since the mousedown executes over the basic click event. Any ideas? Keep in mind that it can't be dependent on a mouseUp event since the drag and drop can't have it.

Never, never use DoEvents() to solve a problem. A Timer can be made to work. But it is not the correct way to go about it. You want to start a drag when the user moved the mouse enough while holding down the left button. Like this:
Private downPos As Point
Private Sub DataGridView1_MouseDown(sender As Object, e As MouseEventArgs) Handles DataGridView1.MouseDown
downPos = e.Location
End Sub
Private Sub DataGridView1_MouseMove(sender As Object, e As MouseEventArgs) Handles DataGridView1.MouseMove
If e.Button = MouseButtons.Left Then
If Math.Abs(downPos.X - e.X) >= SystemInformation.DoubleClickSize.Width Or
Math.Abs(downPos.Y - e.Y) >= SystemInformation.DoubleClickSize.Height Then
Dim hit = DataGridView1.HitTest(downPos.X, downPos.Y)
If hit.RowIndex >= 0 Then
'' Start dragging row
''...
End If
End If
End If
End Sub

Related

VB.NET TableLayout MouseEnter and leave event

I'm trying to do something that actually looks "simple" since several hours, but I cannot understand how to do it...and lurking over SO or different sites it seems that maybe is not that obvious.
The question is simple: i have a tableLayoutPanel with multiple rows, each one of them contains a panel, that contains several other controls.
I just want that when the mouse enters a row, the row background changes and when the mouse leave that row, it comes back to original color.
These are the simple event trappers, where pnlLayoutRow is the name of the panel containing the other controls:
Private Sub devRowMouseEnter(sender As System.Object, e As EventArgs) Handles pnlLayoutrow.MouseEnter
pnlLayoutrow.BackColor = Drawing.Color.FromArgb(&HFFFFEEAA)
End Sub
Private Sub devRowMouseLeave(sender As System.Object, e As EventArgs) Handles pnlLayoutrow.MouseLeave
pnlLayoutrow.BackColor = Drawing.Color.FromArgb(&HFFE7DEBD)
End Sub
The problem is: mouseEnter is correctly fired each time I enter the row, but Mouseleave is fired as soon as the mouse reach one of the controls inside the panel..that drives me crazy.
In other environment, I would solve this placing a transparent object all over the panel and trapping the mouseEnter and leave for that object..but it seems in VB trasparent objects do not exist.
Hope I have been clear in my explanation..it is pretty late in the night and I'm a bit tired.
thank you in advance
hope someone can help me
Cristiano
This version of your mouse leave event checks that the mouse is still within the bounds of your TableLayoutPanel and if it is then it exits without changing the color
Private Sub devRowMouseLeave(sender As System.Object, e As EventArgs) Handles pnlLayoutRow.MouseLeave
Dim p As Point = Me.PointToClient(MousePosition)
If p.Y > pnlLayoutRow.Top And p.Y < (pnlLayoutRow.Top + pnlLayoutRow.Height) And p.X > pnlLayoutRow.Left And p.X < (pnlLayoutRow.Left + pnlLayoutRow.Width) Then
Exit Sub
Else
pnlLayoutRow.BackColor = Drawing.Color.FromArgb(&HFFE7DEBD)
End If
End Sub
It seems to work ok for me,so I hope it is the same for you.
I've had a Google about mouse polling rates and by default, in windows, it's 125hz which might seem OK. However, if you move the mouse quickly, the mouse will enter and leave the panel more quickly that windows can detect it. Because of this, sometimes the .MouseEnter and .MouseLeave events don't fire. So I have here an alternative which will at least detect when the mouse leaves the panel. Add a Timer you your form called tmrPanelLeave
Private Sub devRowMouseEnter(sender As System.Object, e As EventArgs) Handles pnlLayoutRow.MouseEnter
pnlLayoutRow.BackColor = Drawing.Color.FromArgb(&HFFFFEEAA)
tmrPanelLeave.Start()
End Sub
Private Sub tmrPanelLeave_Tick(sender As Object, e As EventArgs) Handles tmrPanelLeave.Tick
Dim p As Point = Me.PointToClient(MousePosition)
If p.Y > pnlLayoutRow.Top And p.Y < (pnlLayoutRow.Top + pnlLayoutRow.Height) And p.X > pnlLayoutRow.Left And p.X < (pnlLayoutRow.Left + pnlLayoutRow.Width) Then
Exit Sub
Else
pnlLayoutRow.BackColor = Drawing.Color.FromArgb(&HFFE7DEBD)
tmrPanelLeave.Stop()
End If
End Sub

How to change progress bar value by dragging mouse in vb.net

I am developing a media player and I'm trying to change value of Progress Bar using mouse cursor.
what i want is to set the value of progress bar where mouse cursor points after clicking + Dragging.
A progress bar is not the correct control to use for this. You should use a TrackBar instead.
But it can be made to work, with about -10 elegance points. The trickiest problem with ProgressBar is that it animates progress. That makes it slow to respond to your mouse moves. That animation can be disabled, but not perfectly. Closest you can get is:
Private Shared Sub ChangeProgress(bar As ProgressBar, e As MouseEventArgs)
If e.Button = Windows.Forms.MouseButtons.Left Then
Dim mousepos = Math.Min(Math.Max(e.X, 0), bar.ClientSize.Width)
Dim value = CInt(bar.Minimum + (bar.Maximum - bar.Minimum) * mousepos / bar.ClientSize.Width)
'' Disable animation, if possible
If value > bar.Value And value < bar.Maximum Then
bar.Value = value + 1
bar.Value = value
Else
bar.Value = value
End If
End If
End Sub
And call it from MouseDown and MouseMove event handlers:
Private Sub ProgressBar1_MouseMove(sender As Object, e As MouseEventArgs) Handles ProgressBar1.MouseMove
ChangeProgress(ProgressBar1, e)
End Sub
Private Sub ProgressBar1_MouseDown(sender As Object, e As MouseEventArgs) Handles ProgressBar1.MouseDown
ChangeProgress(ProgressBar1, e)
End Sub
It is workable, you'll notice that getting to 100% is a bit awkward. But, really, use a TrackBar instead. It was made to do this.

changing calculate button to restart button after clicked

Is there any way to change a button to another button while running the program, i.e when the user clicks a button called "display", it calculates the results, then "display" turns into "Restart?" and if the user clicks that it restarts the program? I would like to change btnDisplay to btnRestart:
Private Sub btnDisplay_Click(sender As Object, e As EventArgs) Handles btnDisplay.Click
' displays a student's grade
Double.TryParse(txtEarned.Text, dblEarned)
For Each minimum As Double In dblMinimumPoints
If dblEarned >= minimum Then
lblGrade.Text = strGrade(gradeIndex)
gradeIndex += 1
End If
Next
txtEarned.ReadOnly = False
btnDisplay.Enabled = False
End Sub
I suppose there are multiple ways to do this. One is to have two buttons, btnDisplay and btnRestart, each with desired Text, that are laid on top of each other in the form designer. Alternate which one is visible when they are clicked.
Private Sub btnDisplay_Click(sender As Object, e As EventArgs) Handles btnDisplay.Click
' displays a student's grade
Double.TryParse(txtEarned.Text, dblEarned)
For Each minimum As Double In dblMinimumPoints
If dblEarned >= minimum Then
lblGrade.Text = strGrade(gradeIndex)
gradeIndex += 1
End If
Next
txtEarned.ReadOnly = False
btnDisplay.Visible = False
btnReset.Visible = True
End Sub
I'm not sure what you mean by saying that btnRestart will "restart the program", but presumably in its click event you would likewise hide it and make btnDisplay visible again.
(Also you might want to add some Try...Finally error handling in these events, so that even if something goes wrong, you can be sure the Visible lines will be executed.)
In your handler onclick and add a select case based on the .text attribute, then if the text is display update it it to restart, if it is restart then add a goto to where you want the script to start from on restart.
EDIT, below I have added the codetorun as a function which is probably a better solution than goto:
Private Sub btnDisplay_Click(sender As Object, e As EventArgs) Handles btnDisplay.Click
Select Case btnDisplay.Text
Case "Submit"
codeiwanttorun()
btnDisplay.Text = "Restart"
Case "Restart"
codeiwanttorun()
End Select
End Sub
Private Function codeiwanttorun()
Double.TryParse(txtEarned.Text, dblEarned)
For Each minimum As Double In dblMinimumPoints
If dblEarned >= minimum Then
lblGrade.Text = strGrade(gradeIndex)
gradeIndex += 1
End If
Next
End Function

Combining mouseEvents on label in VB.NET

I want to combine MouseEnter with MousePressed on a label.
Public Sub populateGrid()
lblTest.BackColor()
lblTest.BackColor = System.Drawing.Color.Red
gbWorkflow.Controls.Add(lblTest)
For j As Integer = 1 To 40
For i As Integer = 1 To 20
Dim L As New Label
L.Size = New Size(30, 30)
L.Text = "L:" + i.ToString + j.ToString
L.BackColor = Color.AliceBlue
Dim x, y As Integer
Dim loc As Point = gbWorkflow.Location
y = loc.Y * (i * 8) '- (gbWorkflow.Height + L.Size.Height) * i
x = loc.X * (j * 8)
L.Location = New Point(x, y)
gbWorkflow.Controls.Add(L)
AddHandler L.MouseEnter, AddressOf L_Enter
AddHandler L.MouseLeave, AddressOf L_Leave
Next
Next
End Sub
Private Sub L_Enter(ByVal sender As Object, ByVal e As System.EventArgs)
Dim TheLabel As Label = CType(sender, Label)
TheLabel.BackColor = Color.Red
End Sub
My idea was to create a method that triggers on MouseDown and changes the value of a boolean variable. I would then use that variable as a condition to apply the changes to the labels. However, that doesnt seem to work...
How can I achieve this in the best way? Or, at all?
Pseudo-code:
When mouse enter label:
if left mousebutton is pressed then
do stuff with the label
Edit:
It also has to work when the mousebutton is still pressed and the cursor is dragged over several labels. All the labels that the cursor crosses while the left button is pressed should be changed.
The MouseDown event delivers what you are after. Sample code:
Private Sub L_MouseDown(sender As Object, e As System.Windows.Forms.MouseEventArgs)
If (e.Button = Windows.Forms.MouseButtons.Left) Then
'Do stuff
End If
End Sub
Adding the event handler:
AddHandler L.MouseDown, AddressOf L_MouseDown
--- UPDATE
As said, you cannot accomplish directly what you want but there are many alternative ways to deliver an equivalent performance. For example:
Boolean flag indicating whether one of the target labels has been clicked (MouseDown) + MouseEnter performing the modifications only if this flag is true. Sample code:
Private LWasClicked As Boolean = False
Private Sub L_MouseDown(sender As Object, e As System.Windows.Forms.MouseEventArgs)
If (e.Button = Windows.Forms.MouseButtons.Left And Not LWasClicked) Then
LWasClicked = True
End If
End Sub
Private Sub L_MouseEnter(sender As Object, e As System.EventArgs)
If (LWasClicked) Then
'Do stuff
End If
End Sub
With the code above, you can "activate the editing" by just clicking on any label (or on a specific one); once it is activated, you can just pass the mouse over any label and the actions will be performed. You will also have to set an event to de-activate this behaviour (example: new Click/MouseDown). As you can see, this delivers an equivalent performance to what you want and is compatible with how events work.
CLARIFICATION: I think that this (or any other alternative on these lines) delivers an excellent performance. If still you don't want that and prefer to do everything with the mouse-button pressed, you would have to rely on something different (e.g., position of the mouse on the screen, analysis triggered by other means; or even events from different threads). What is clear is that what you aim cannot be accomplished with one-thread events of different controls (a new event cannot be started before the previous one has ended).

Detect if mouse stop moving vb.net

I would like to stop the timer whenever a mouse stops moving inside a groupbox
As of now, I start the timer when the mouse hover at the groupbox and stops it when it leaves the group box.
Private Sub gbxMouseMap_MouseHover(sender As Object, e As System.EventArgs) Handles gbxMouseMap.MouseHover
Timer.Start()
End Sub
Private Sub gbxMouseMap_MouseLeave(sender As Object, e As System.EventArgs) Handles gbxMouseMap.MouseLeave
Timer.Stop()
End Sub
In the MouseMove event set a class varible named LastMoveTime to the current timer elapsed time. In the MouseHover event check to see if LastMoveTime has reached the timeout period, if so stop the timer.
I will get you started...
Private LastMoveTime As DateTime
Private MouseTimeoutMilliseconds as Integer = 500
'put inside hover
If LastMoveTime.AddMilliseconds(MouseTimeoutMilliseconds) < Now Then
Timer.Stop()
Else
Timer.Start()
End if
To prevent having to handle this for many controls you can rearrange things a bit and cache the information needed to know if cursor has moved and how long the idle time is, to do this you need a Point variable and a Date variable. The Timer needs to tick all the time. In addition, to balance the cursor Show/Hide calls you need a variable to keep track of its visibility state. Here is the complete code sample:
Private loc As Point, idle As Date, hidden As Boolean,
Private Sub Timer1_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer1.Tick
If loc <> Cursor.Position Then
If hidden Then
Cursor.Show()
hidden = False
End If
loc = Cursor.Position
idle = Date.Now
ElseIf Not hidden AndAlso (Date.Now - idle).TotalSeconds > 3 Then
Cursor.Hide()
hidden = True
End If
End Sub
This Timer can tick each 1/2-1 seconds depending on how responsive you want it, the idle time is set to 3 seconds. The code should be easy to understand when you read it and give it some thought, if not ask