Getting a panel within a panel with mouse position - vb.net

I've been looking for this thing... It should be working yet it is not. There must be something I don't get understand or that I'm missing. It's quite a simple problem but I can't seem to solve it.
I got Panel1 and Panel2 as shown in this picture.
I want to catch when mouse is over Panel2 within Panel1 MouseLeave event. My code goes like this :
Private Sub Panel1_MouseLeave(sender As Object, e As EventArgs) Handles Panel1.MouseLeave
If sender.ClientRectangle.Contains(PointToClient(Control.MousePosition)) Then
For Each ctrl As Object In sender.controls
If ctrl.ClientRectangle.Contains(PointToClient(Control.MousePosition)) Then Exit Sub
Next
If Not IsNothing(sender.BackgroundImage) Then sender.BackgroundImage = Nothing
End If
End Sub
Private Sub Panel2_MouseLeave(sender As Object, e As EventArgs) Handles Panel2.MouseLeave
If Not sender.ClientRectangle.Contains(PointToClient(Control.MousePosition)) Then
If Not IsNothing(sender.BackgroundImage) Then sender.BackgroundImage = Nothing
End If
End Sub
I'm successfully getting into the first if, but the 2nd one within the For Each just never equals true. So I thought maybe there was a problem with the 2nd panel, so I tried placing the same code for Panel2 MouseLeave, but it's working just fine.
I really need this code to work for a big control flickering problem I'm having.

Thanks to Hans Passant for the hint. I just had to call the PointToClient with the right control :
Private Sub Panel1_MouseLeave(sender As Object, e As EventArgs) Handles Panel1.MouseLeave
If sender.ClientRectangle.Contains(Panel1.PointToClient(Control.MousePosition)) Then
For Each ctrl As Object In sender.controls
If ctrl.ClientRectangle.Contains(ctrl.PointToClient(Control.MousePosition)) Then Exit Sub
Next
If Not IsNothing(sender.BackgroundImage) Then sender.BackgroundImage = Nothing
End If
End Sub

Related

How to share events between forms

So i have a tray icon that should behave the same way between 3 forms. I then created this code:
Private Sub TrayForm_MouseClick(sender As Object, e As MouseEventArgs) Handles NotifyIcon1.MouseClick
If e.Button = MouseButtons.Right Then
If Not Application.OpenForms().OfType(Of TrayForm).Any = 1 Then
TrayForm.ContextMenuStrip1.Show(Cursor.Position)
End If
End If
End Sub
Which is used to handle the tray icon. How can i do to share this event between the forms so i don't have to place this same code on every form?
How are event handlers working exactly? I looked online and on MSDN and it is not clear to me.
Thanks
Are you sure that you want to share the event, and not juste the code that will handle the event?
If you don't want to copy and paste your code, which you need to handle the events of more than one form, here's a way to do it:
Declare the sub which contains the code needed to handle the event as a public shared sub. Like this:
Public Shared Sub TrayForm_MouseClick(sender As Object, e As MouseEventArgs)
So, now you have a Sub which can handle the event you want to handle from all three forms.
Now, when you initialize those forms, add a line to make the shared Sub handle the event you want it to handle:
AddHandler NotifyIcon1.MouseClick, AddressOf ProjectName.FileName.TrayForm_MouseClick
ProjectName.FileName is meant here to be the path to refer to the shares Sub inside the file where you put it. I usually name it like ProjectNameUtils.vb or something like that.
If you just want to avoid copy and pasting your Sub so you don't have to modify it at several places every time you change something, this could be a way to achieve that.
As Stipulated by Hans Passant:
Sub Eclass_EventHandler(sender As Object, e As MouseEventArgs) Handles Me.MouseClick
If e.Button = MouseButtons.Right Then
If Not Application.OpenForms().OfType(Of TrayForm).Any = 1 Then
Me.ContextMenuStrip1.Show(Cursor.Position)
End If
End If
End Sub
On the Trayform.VB just did the trick.
But about the shared event. i Have one that would have to be:
Private Sub FormClosingEVENT(sender As System.Object, e As System.Windows.Forms.FormClosingEventArgs) Handles MyBase.FormClosing
If Not FromMenu Then e.Cancel = True
Me.WindowState = FormWindowState.Minimized
'Application.Exit()
End Sub
How should i handle this?

Improve UI responsiveness on windows form application

I am currently working on a project and decided to create a user interface for it using visual studio with a windows forms application(Visual Basic).
The problem I'm facing is that the user interface doesn't respond as quickly and smoothly as I'd like it to.
Mainly, I am using pictures as buttons to make the user form look more modern.
However, when I hover my mouse over a "button" it takes a while until the "highlighted button" appears.
P1 is the picture of the "normal button" and P2 is the picture of the "highlighted button".
Here is the short code I have for now:
Public Class Main
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
End Sub
Private Sub PictureBox1_MouseHover(sender As Object, e As EventArgs) Handles P1.MouseHover
P1.Visible = False
P2.Visible = True
End Sub
Private Sub P2_MouseClick(sender As Object, e As MouseEventArgs) Handles P2.MouseClick
'Call cmdInit()
'Call cmdConnectRobot()
'Call cmdUnlock()
End Sub
Private Sub Main_MouseHover(sender As Object, e As EventArgs) Handles Me.MouseHover
If P2.Visible = True Then
P2.Visible = False
P1.Visible = True
End If
End Sub
Private Sub P4_Click(sender As Object, e As EventArgs) Handles P4.Click
End Sub
End Class
Another problem I'm facing is that when I call other subs, the user form becomes unresponsive while the sub is running.
I researched and found that I could implement multi threading or async tasks but I'm a bit lost and would be extremely grateful if someone could guide me or point me in the right direction.
Thanks in advance!!
In this case your UI is responsive, however the MouseHover event is only raised once the mouse cursor has hovered over the control for a certain amount of time (default is 400 ms), which is what is causing the delay.
What you are looking for is the MouseEnter event, which is raised as soon as the cursor enters ("touches") the control:
Private Sub P1_MouseEnter(sender As Object, e As EventArgs) Handles P1.MouseEnter
P1.Visible = False
P2.Visible = True
End Sub
You can then use that together with the MouseLeave event on the second picture box to switch back to the non-highlighted image:
Private Sub P2_MouseLeave(sender As Object, e As EventArgs) Handles P2.MouseLeave
P1.Visible = True
P2.Visible = False
End Sub
However switching picture boxes like this is not optimal. I recommend you to look into how you can use Application Resources, then modify your code to only switch the image that one picture box displays.
Here are the basic steps:
Right-click your project in the Solution Explorer and press Properties.
Select the Resources tab.
To add an image either:
a. Drag and drop the image onto the resource pane.
b. Click the arrow next to the Add Resource... button and press Add Existing File....
Now, in your code add this right below Public Class Form1:
Dim ButtonNormal As Image = My.Resources.<first image name>
Dim ButtonHighlighted As Image = My.Resources.<second image name>
Replace <first image name> and <second image name> with the names of your button images.
Now you only need one picture box for the button:
Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
P1.Image = ButtonNormal
End Sub
Private Sub P1_MouseEnter(sender As System.Object, e As System.EventArgs) Handles P1.MouseEnter
P1.Image = ButtonHighlighted
End Sub
Private Sub P1_MouseLeave(sender As System.Object, e As System.EventArgs) Handles P1.MouseLeave
P1.Image = ButtonNormal
End Sub
I'll start by saying i'm not a programmer by trade, and i'm sure someone will point out better ways of doing these things, but in regards to the threading question it's fairly simple to implement.
Imports System.Threading
Public Class Form1
Dim WorkerThread As New Thread(AddressOf DoWork)
'WorkerThread' can be any name you like, and 'DoWork' is the name of the sub you want to run in the new thread, and is launched by calling:
WorkerThread.start()
However there is a catch, the new thread is not able to interact directly with the GUI, so you cannot change textbox text etc... I find the easiest way to get changes made to the GUI is to drag a timer onto your form, and have the new thread change variables (pre-defined just below Public Class Form1), then use the Timer1 Tick event to monitor the variables and update the GUI if there are any changes.

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

DataGridView.rows.Cells.Style.BackColor doesn't work with MdiParent in form load event

It really drives me crazy, I have a form, I am calling a public sub called "timerss" in the form load event, when i run my form the sub "timerss" works perfectly, but when i add "Me.MdiParent = MDIParent1" in load event the sub "timerss" doesn't work!! i am really confused here!! any idea please.
Private Sub Main_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
Me.MdiParent = MDIParent1
timerss()
End Sub
update1:\ check the print screen of the result when running my form with and without setting MdiParent!
update2: I managed to fix part of the problem which is i got the data but what i want now is to set the color of the time cells with red, as i said the sub don't want to work, the timerss sub is:
For m As Integer = 0 To DataGridView1.Rows.Count - 1
If DataGridView1.Rows(m).Cells(4).Value > DataGridView1.Rows(m).Cells(9).Value Then
DataGridView1.Rows(m).Cells(4).Style.BackColor = Color.Red
MsgBox("red")
End If
Next
as u c in the above code i put a msgbox just to make sure that the code is working, so when i run my form the msgbox appears, but the backcolor function doesn't work when i set the MdiParent.
I don't know why the behavior is different without MDIParent, but you could try calling the sub from the DataBindingComplete event.
I had a similar problem and solved it using the event.

How to wait for line of code to finish before moving onto the next line

I'm using Visual Basic 2010, and within my form shown sub I need two buttons to be pressed , however I need the first button's code to complete before the moving on to pressing the next button. Is there any way to allow this to happen? Thanks :)
Private Sub Form1_Shown(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Shown
BindingNavigatorMoveLastItem.PerformClick()))
'I need this next button click to be carried out after the one above has completely finished
BindingNavigatorMovePreviousItem.PerformClick()))
End Sub
Use methods instead of "button-clicks":
Private Sub Form1_Shown(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Shown
MoveLastItem()
MovePreviousItem()
End Sub
Private Sub MoveLastItem()
bindingSource1.MoveLast();
End Sub
Private Sub MovePreviousItem()
bindingSource1.MovePrevious();
End Sub
You just have call these methods from the button-click events handlers as well.
Private Sub BindingNavigatorMoveLastItem_Clicked(sender As Object, args As EventArgs) Handles BindingNavigatorMoveLastItem.Click
MoveLastItem()
End Sub
Private Sub BindingNavigatorMovePreviousItem_Clicked(sender As Object, args As EventArgs) Handles BindingNavigatorMovePreviousItem.Click
MovePreviousItem()
End Sub
I must admit I don't do VB, but I came across this page and it might be useful to you.
http://msdn.microsoft.com/en-us//library/system.windows.forms.application.doevents.aspx
If that is not relevant, in your situation I would either use the buttons to set flags and simply if-test the flags, or create a do-while loop so that the code can finish executing while the conditions are met. Careful with those, however, as infinite loops are something they are good at.
Another thought is to enable the second button in the last line of the code of the first button?
Hope something helps. Apologies if it is of no use.