C#: How to simulate Mouse Hover event using Timer - c#

I have a fom which has one user control docked to fill.
this user control displays different images.each image has Id and I have a list of imageId vs imageDetail object dictionary.
Mouse Move event of this user control is captured and i am displaying current X and Y position of mouse in tool tip.
I also want to display image detail in tool tip when user keeps the mouse over image for some time.
I tried to do this with Mouse Hover event but it only raised when mouse enters in user control bound. after this if i move mouse within user control mouse hover event does not fire...
How can i display current X, Y position along image detail in tool tip.
is there any way to simulate Mouse Hover event within Mouse Move using some timer.
Is there any sample code..
I solved this problem by
public partial class Form1 : Form
{
Timer timer;
bool moveStart;
int count = 0;
Point prev;
public Form1()
{
InitializeComponent();
timer = new Timer();
timer.Interval = 1000;
timer.Tick += new EventHandler(timer_Tick);
}
void timer_Tick(object sender, EventArgs e)
{
this.timer.Stop();
this.moveStart = false;
this.toolTip1.SetToolTip(this, string.Format("Mouse Hover"));
this.textBox1.Text = (++count).ToString();
}
private void Form1_MouseMove(object sender, MouseEventArgs e)
{
if (this.prev.X == e.X && this.prev.Y == e.Y)
return;
if (moveStart)
{
this.prev = new Point(e.X, e.Y);
this.timer.Stop();
this.toolTip1.SetToolTip(this, string.Format("Mouse Move\nX : {0}\nY : {1}", e.X, e.Y));
this.timer.Start();
}
else
{
moveStart = true;
}
}
}

The simplest way would be to call the MouseOver subroutine from the MouseMove subroutine as such:
void MouseMove(object sender, MouseEventArgs e)
{
//Call the MouseHover event
MouseHover(sender, e);
}
void MouseHover(object sender, EventArgs e)
{
//MouseHover event code
}
If you want more control over when and how to display your tooltip, however, you'll need to do something similar to the following:
Declare a listening variable at class level.
Hook to the MouseHover event so the listening variable is turned on when the mouse enters.
Hook to the MouseLeave event so the listening variable is turned off when the mouse leaves.
Put your tooltip code in the MouseMove handler so it displays your tooltip if the listening variable is on.
Here's some code to demonstrate what's I outlined above.
class Form1
{
bool showPopup = false;
void MouseHover(object sender, EventArgs e)
{
showPopup = true;
}
void MouseLeave(object sender, EventArgs e)
{
showPopup = false;
toolTip.Hide(this);
}
void MouseMove(object sender, MouseEventArgs e)
{
if (showPopup)
{
toolTip.Show("X: " + e.Location.X + "\r\nY: " + e.Location.Y,
this, e.Location)
}
}
}
Of course, you'll have to add a ToolTip with the name toolTip and associate the various methods (subroutines) with the appropriate events of your control (Form, PictureBox, etc).

Related

How do I stop an animation with a timer if the animated object came to a specific location?

I am trying to do some animations with panels and a timer in a C# Windows Forms project. Currently, there is a panel (in my code called 'pnSideBlock') which is located at the left edge of the window. Right next to it is a button.
The idea is that if the mouse enters the button, then the panel should relocate outside of the window (in my project the panel has a width of 20px, therefor I make its new location 20px outside of the window) and will move into it again with the help of a timer. As soon as the panel has reached a specific location, in my case 0px, then the timer should stop and the panel should stop moving.
But at the moment, the timer just keeps on going, which causes the panel to keep moving to the right.
private void btnMainMenu_MouseEnter(object sender, EventArgs e)
{
pnSideBlock.Left = -20;
timerForAnim.Enabled = true;
if(pnSideBlock.Left == 0)
{
timerForAnim.Enabled = false;
}
}
private void btnMainMenu_MouseLeave(object sender, EventArgs e)
{
timerForAnim.Enabled = false;
}
private void timerForAnim_Tick(object sender, EventArgs e)
{
pnSideBlock.Left += 1;
}
according to your code you need to change it to be like this:
private void btnMainMenu_MouseEnter(object sender, EventArgs e)
{
pnSideBlock.Left = -20;
timerForAnim.Enabled = true;
}
private void btnMainMenu_MouseLeave(object sender, EventArgs e)
{
timerForAnim.Enabled = false;
}
private void timerForAnim_Tick(object sender, EventArgs e)
{
pnSideBlock.Left += 1;
if(pnSideBlock.Left == 0)
{
timerForAnim.Enabled = false;
}
}
this change is required becouse btnMainMenu_MouseEnter happen only once when you enter to the button with the mouse.
and you need to check if the panel in place after every move.
Something similar, using a async Method.
Make your Button's MouseEnter handler async and call the async Task SlidePanel() method, specifying the initial and final position of the Control to slide and the speed of the animation (expressed in milliseconds).
When the Control is first entered, it's MouseEnter handler is detached (so it won't be raised again if the mouse pointer enters it while the animation is playing) and is be wired again when the animation finishes.
You can interact with the Button as usual.
The animation will be performed to its end even if the Button shows a modal Window when clicked (a MessageBox, for example).
Visual behaviour:
private async Task SlidePanel(Control control, int start, int end, int speed)
{
while (start < end)
{
await Task.Delay(speed);
start += 1;
control?.BeginInvoke(new Action(() => control.Left += 1));
}
}
private async void btnSlider_MouseEnter(object sender, EventArgs e)
{
btnMainMenu.MouseEnter -= btnMainMenu_MouseEnter;
pnSideBlock.Left -= pnSideBlock.Width;
await SlidePanel(pnSideBlock, pnSideBlock.Left, pnSideBlock.Width, 100);
btnMainMenu.MouseEnter += btnMainMenu_MouseEnter;
}

Drag'n Drop : tell the sender when drop occurs

I'm using c# 3.5 / winforms
On my form, I have 2 picturebox PB1 and PB2 (and lots of others controls), in a panel.
The user can drag PB1 to PB2. But he can also cancel the drop by release the left button anywhere on the form or outside the form.
PB1 can be dragged a fixed number of times. When the drag start, I decrease a variable in PB1 and if it reach 0, the PB became invisible.
But if the user cancel the drag, PB1 must know that to increase the variable and set the visibility of PB1.
My problem is : how PB1 can know when a drag is canceled (or actually, dropped, even on a valid control) ? Remember that the user can release the drag outside of the form, so I can't use the Drop event on the form. I try the GiveFeedback and the QueryContinueDrag events, but they are fired as long as the drag continue, but not when it stop.
Some code :
class COPGOJetonImage
{
private PictureBox PB1;
public COPGOJetonImage()
{
PB1 = new PictureBox();
//here I initialize PB1
((Control)PB1).AllowDrop = true; //in case of
PB1.MouseDown += OnMouseDown;
}
public void OnMouseDown(object sender, MouseEventArgs ev)
{
PB1.DoDragDrop(PB1.Image, DragDropEffects.Copy);
}
}
"there are 1 to 4 valid targets."
In this example we are dragging pictureBox1, and pictureBox2 thru pictureBox5 are the valid drop targets. We create a DataObject with a custom name to encapsulate pictureBox1 during the drag/drop operation. In the drop targets, we only allow a drop if the custom name is present in the thing being dragged. This ensures we only get a DragDrop event from pictureBox1 itself, and we know it's safe to decrement our drop counter. We can retrieve pictureBox1 back from the DataObject and change its state so that it can no longer be dropped:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private int DropsLeft = 5;
private string DataFormatName = "YourUniqueDataFormatNameHere";
private void Form1_Load(object sender, EventArgs e)
{
pictureBox1.MouseMove += PictureBox1_MouseMove;
PictureBox[] pbs = new PictureBox[] { pictureBox2, pictureBox3, pictureBox4, pictureBox5 };
foreach (PictureBox pb in pbs)
{
pb.AllowDrop = true;
pb.DragEnter += Pb_DragEnter;
pb.DragDrop += Pb_DragDrop;
}
}
private void PictureBox1_MouseMove(object sender, System.Windows.Forms.MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
DataObject data = new DataObject(DataFormatName, pictureBox1);
pictureBox1.DoDragDrop(data, DragDropEffects.Copy);
}
}
private void Pb_DragEnter(object sender, DragEventArgs e)
{
if (e.Data.GetDataPresent(DataFormatName))
{
e.Effect = DragDropEffects.All;
}
else
{
e.Effect = DragDropEffects.None;
}
}
private void Pb_DragDrop(object sender, DragEventArgs e)
{
DropsLeft--;
// retrieve the data
PictureBox pb = (PictureBox)e.Data.GetData(DataFormatName);
if (DropsLeft == 0)
{
MessageBox.Show("No more drops left!");
pb.Enabled = false;
pb.BackColor = Color.Red; // for visual effect
}
}
}

How can I move a button with mousehover?

I've made a TextBox that retains what you type, and when you click the button associated it gives you a messagebox. When people want to click no, I want the button to change location so people cannot click it so they are forced to click yes,Well the problem is mousehover works just 1 time and does not go back to initial position after i leave my pointer out. Can you help me? Here is the code:
{
MsgBox = new CustomMsgBox();
MsgBox.label1.Text = Text;
MsgBox.button1.Text = btnOK;
MsgBox.button2.Text = btnCancel;
MsgBox.Text = Caption;
result = DialogResult.No;
MsgBox.ShowDialog();
return result;
}
private void button2_Click(object sender, EventArgs e)
{
button2.Location = new Point(25, 25);
}
private void button2_MouseHover(object sender, EventArgs e)
{
button2.Location = new Point(+50, +50);
}
private void button2_MouseLeave(object sender, EventArgs e)
{
button2.Location = new Point(+100, +100);
}
You should not use MouseLeave because when you move the button in the MouseHover, the button will move so the mouse will leave the button area. Meaning the No button will flip from the original position to the new position and back again all the time. What you could do is use the MouseMove to see if the user moved away from the area where the Button2 was originally and then move it back. Or include a non-visible control, like an empty label behind the button2. And set the MouseLeave on the label instead.
Oh and don't forget to set button2.TabStop = false, otherwise the user can use tab to get to the button.
Made a quick and dirty proof of concept for this, hope that helps ;)
public partial class Form1 : Form
{
private Rectangle buttonRectangle;
private bool checkRectangle = false;
public Form1()
{
InitializeComponent();
button2.TabStop = false;
buttonRectangle = button2.ClientRectangle;
buttonRectangle.Location = button2.Location;
}
private void button2_Click(object sender, EventArgs e)
{
button2.Location = new Point(25, 25);
}
private void button2_MouseHover(object sender, EventArgs e)
{
button2.Location = new Point(50, 50);
checkRectangle = true;
}
private void Form1_MouseMove(object sender, MouseEventArgs e)
{
if (!checkRectangle)
{
return;
}
if (!buttonRectangle.Contains(e.X, e.Y))
{
checkRectangle = false;
button2.Location = buttonRectangle.Location;
}
}
}
The buttonRectangle is set based on where the button is found during construction of the form. It has a contains method that can be used to check if a certain point (mouse move) is contained in it.
I also set the button2.TabStop to false so it will no longer be active during tab cycles.
When your hover (can change this to mouse enter, but just used your code) event fires, I set checkRectangle to true. I use this in the mouse move event handler to see if anything should be checked (prevents from doing anything when the mouse is not "over" the button).
If the buttonRectangle and the mouse location are not intersected this means we left the area where the button was, so we can move the button back.

Checking if panel has moved during MouseDown

I have a panel, that can be moved left or right (chosen automatically according to its current position, distance is static) by click. Also, the user can drag the panel vertically however he wants by clicking the panel, holding the button and moving his mouse. The problem is, that the panel does the left/right move also, when it is dropped after being moved vertically, so the user has to click it again afterwards, to get to correct side (left/right). Here are the methods I am using:
Adding eventhandlers to panel(called Strip here)
Strip.MouseDown += new MouseEventHandler(button_MouseDown);
Strip.MouseMove += new MouseEventHandler(button_MouseMove);
Strip.MouseUp += new MouseEventHandler(button_MouseUp);
Strip.Click += new EventHandler(strip_Click);
And here all the methods mentioned above:
void button_MouseDown(object sender, MouseEventArgs e)
{
activeControl = sender as Control;
previousLocation = e.Location;
Cursor = Cursors.Hand;
}
void button_MouseMove(object sender, MouseEventArgs e)
{
if (activeControl == null || activeControl != sender)
return;
var location = activeControl.Location;
location.Offset(0, e.Location.Y - previousLocation.Y);
activeControl.Location = location;
}
void button_MouseUp(object sender, MouseEventArgs e)
{
activeControl = null;
Cursor = Cursors.Default;
}
void strip_Click(object sender, EventArgs e) // The one moving strip to left or right
{
activeControl = sender as Control;
if (activeControl.Left != 30)
activeControl.Left = 30;
else
activeControl.Left = 5;
}
How to make the panel not move left or right when it was moved vertically?
You'll need to distinguish between a click and a drag. So add a private field named "dragged".
private bool dragged;
In the MouseDown event handler add:
dragged = false;
In the MouseMove event handler add:
if (Math.Abs(location.Y - previousLocation.Y) >
SystemInformation.DoubleClickSize.Height) dragged = true;
In the Click event handler add:
if (dragged) return;

how to Make the Mouse Freeze c#

i want the mouse to freez (cant move) when mouse down
thanks
I used a tableLayoutPanel for your reference (Just remember to implement the code to the Control that is in the front):
OPTION1: Reset the mouse position:
Define two global variables:
bool mousemove = true;
Point currentp = new Point(0, 0);
Handel MouseDown Event to update mousemove :
private void tableLayoutPanel1_MouseDown(object sender, MouseEventArgs e)
{
int offsetX = (sender as Control).Location.X + this.Location.X;
int offsetY = (sender as Control).Location.Y + this.Location.Y;
mousemove = false;
currentp = new Point(e.X+offsetX, e.Y+offsetY); //or just use Cursor.Position
}
Handel MouseMove to disable/enable move:
private void tableLayoutPanel1_MouseMove(object sender, MouseEventArgs e)
{
if (!mousemove)
{
this.Cursor = new Cursor(Cursor.Current.Handle);
Cursor.Position = currentp;
}
}
Reset mousemove while Mouseup
private void tableLayoutPanel1_MouseUp(object sender, MouseEventArgs e)
{
mousemove = true;
}
OPTION2: Limit mouse clipping rectangle:
Limit it while MouseDown:
private void tableLayoutPanel1_MouseDown(object sender, MouseEventArgs e)
{
this.Cursor = new Cursor(Cursor.Current.Handle);
Cursor.Position = Cursor.Position;
Cursor.Clip = new Rectangle(Cursor.Position, new Size(0, 0));
}
Release it after MouseUp:
private void tableLayoutPanel1_MouseUp(object sender, MouseEventArgs e)
{
this.Cursor = new Cursor(Cursor.Current.Handle);
Cursor.Position = Cursor.Position;
Cursor.Clip = Screen.PrimaryScreen.Bounds;
}
You can't.
Mouse acts in the OS Layer, not your app... even if you freeze your app, mouse will be able to run.
You can try to disconnect the mouse driver/port but you do need to ask the user what port the mouse is using as for the OS it's a Input device, just like a pen in a design board and you will not know the one to disconnect.
It's possible, Windows has a dedicated API for it, BlockInput(). Be sure to save all your work when you experiment with it, it is rather effective. You may need to reboot your machine, the thing your user will do when you use it in a program. Here's a sample Windows Forms form that uses it, it needs a button and a timer:
public partial class Form1 : Form {
public Form1() {
InitializeComponent();
timer1.Interval = 3000;
timer1.Tick += new EventHandler(timer1_Tick);
button1.Click += new EventHandler(button1_Click);
}
private void button1_Click(object sender, EventArgs e) {
timer1.Enabled = true;
BlockInput(true);
}
private void timer1_Tick(object sender, EventArgs e) {
timer1.Enabled = false;
BlockInput(false);
}
[System.Runtime.InteropServices.DllImport("user32.dll")]
private static extern bool BlockInput(bool block);
}
You can fake that behavior for your window in the following way:
Remember current cursor and its position.
Set
this.Cursor = Cursors.None;
Draw the remembered cursor at specified position and introduce canExecute flag for all your mouse handlers to disable them during "fake mouse freezing".
Can't you move the mouse pointer somewhere? You could reset its position when moving (which may look ugly).
Setup a low level mouse hook with SetWindowsHookEx and ignore all messages to the HOOKPROC delegate you specified (means not to call CallNextHookEx).

Categories