So here's the problem. I'm using the keyDown event to set a bool to true - and as long as it's true, the mouseMove event paints on a picturebox. Essentially a drawing program. Problem is that as long as I'm holding down the drawing button, the bool seems to toggle on and off, and I get a weird stripey result (see blue line in sample picture). The bool doesn't get turned off in code, so I have no idea what's causing it (well, it gets turned off, but I disabled that part of the code and am still getting the problem).
Any ideas?
Edit: Here is some of the code. I left out the keyUp event because I can disable it and still get the same issue. Even more interestingly, if I let go of the keyboard button, I get a solid straight line, but as long as I hold down the button, it works fine for about a second and then starts doing the stripey thing (similarily to when you hold a button down in text - it waits a bit, then starts repeating the character).
private void Main_KeyDown(object sender, KeyEventArgs e)
{
string clicked = e.KeyData.ToString().ToLower(); // I'm comparing the clicked key to make sure the right button is clicked (there's a controls changing system)
cursorLocation = pictureBox1.PointToClient(System.Windows.Forms.Cursor.Position);
if (clicked == ctkey && MapLoaded)
{
readyForDraw();
pen = new Pen(Color.DodgerBlue, penSize);
}
else if (clicked == tkey && MapLoaded)
{
readyForDraw();
pen = new Pen(Color.Red, penSize);
}
else if (clicked == neutralkey && MapLoaded)
{
readyForDraw();
pen = new Pen(neutralColour, penSize);
}
}
private void pictureBox1_MouseMove(object sender, MouseEventArgs e)
{
if (isDrawing && MapLoaded && addPlayerMode == false)
{
g.DrawLine(pen, cursorLocation, e.Location);
pictureBox1.Invalidate();
pictureBox1.Image = mainBitmap;
cursorLocation = pictureBox1.PointToClient(System.Windows.Forms.Cursor.Position);
}
}
private void readyForDraw()
{
g = Graphics.FromImage(mainBitmap);
isDrawing = true;
saveBackup();
}
Sample picture. Red is drawn using the MouseDown event - works fine. Blue is the keyDown event, broken.
Use Keyboard.GetKeyStates from WPF like so:
public static bool IsDown(Key key) {
return Keyboard.GetKeyStates(key) & KeyStates.Down != 0;
}
and it should work without problems even if your app is WinForms and not WPF.
(Reference PresentationCore.dll from your project)
Related
So i tried to make a button more animated by making that when i hover my mouse over the button its back colour goes slowly from a darker gray to lighter gray, sadly the the MouseHover didn't worked out great for me because i had to use it with if (while, do and for isn't working at all) so i changed it to MouseMove And well that created its own problems, right now the colour getting lighter only when i move my mouse on it, here is the code:
private void BtnPlay_MouseMove(object sender, MouseEventArgs e)
{
byte coloDat = btnPlay.FlatAppearance.MouseOverBackColor.B;
if (btnPlay.FlatAppearance.MouseOverBackColor != Color.FromArgb(68, 68, 68))
{
coloDat++;
btnPlay.FlatAppearance.MouseOverBackColor = Color.FromArgb(coloDat, coloDat, coloDat);
System.Threading.Thread.Sleep(1);
}
}
Im gonna use the code multiple times in the project so is there a way to do this without making a wall of text?
Edit: For avoiding confusion; im trying to do my project with Button.FlatAppearance.MouseOverBackColor and not Button.BackgroundColour.
If you want to create this in WPF, just create a style with a storyboard. In windows forms, you need to use a timer.
The reason a loop didn't work for you is that the loop was running on the same thread as the UI, so the UI wasn't being updated until after your loop was over. To animate an effect in windows forms, you have to let the event function end so that the UI can update and then have your function called again for the next frame. That is what the timer element does.
I created a demo program with two animated buttons. To create buttons with animated background colors I first set up a start color, end color, the amount I want the color to change in each frame, the button the mouse is currently over and the transition progress of each button. I added that last so that I could have the buttons gradually transition back after the mouse was over something else.
private Color startColor = Color.AliceBlue;
private Color endColor = Color.BlueViolet;
private double step = 0.01;
private Button lastOver = null;
private Dictionary<Button, double> transitionProgress = new Dictionary<Button, double>();
Then I attached the event handlers of both of my buttons to the same functions, the functions below. The first uses ContainsKey so that I can make more buttons animated by just assigning them to these event handler functions.
private void demoButton_MouseHover(object sender, EventArgs e)
{
if (sender != lastOver)
{
lastOver = (Button)sender;
if (!transitionProgress.ContainsKey(lastOver))
{
transitionProgress[lastOver] = 0.0;
}
}
}
private void demoButton_MouseLeave(object sender, EventArgs e)
{
lastOver = null;
}
Then I created a Timer with the following event handler. It goes through each button and transitions it based on whether the mouse is currently over that button. It also only updates the background color if it has changed to improve performance.
private void styleUpdate_Tick(object sender, EventArgs e)
{
for (int i = 0; i < transitionProgress.Count; i++)
{
Button button = transitionProgress.Keys.ElementAt(i);
bool changing = false;
if (button == lastOver)
{
if (transitionProgress[button] < 1.0)
{
transitionProgress[button] = Math.Min(1.0, transitionProgress[button] + step);
changing = true;
}
}
else
{
if (transitionProgress[button] > 0.0)
{
transitionProgress[button] = Math.Max(0.0, transitionProgress[button] - step);
changing = true;
}
}
if (changing)
{
double progress = transitionProgress[button];
button.BackColor = Color.FromArgb(
(int)Math.Floor((endColor.R - startColor.R) * progress + startColor.R),
(int)Math.Floor((endColor.G - startColor.G) * progress + startColor.G),
(int)Math.Floor((endColor.B - startColor.B) * progress + startColor.B)
);
}
}
}
The timer has to be enabled and the interval set to 16
this.styleUpdate.Enabled = true;
this.styleUpdate.Interval = 16;
this.styleUpdate.Tick += new System.EventHandler(this.styleUpdate_Tick);
That does seem like a lot of code, but to add it to another button, you just need two more lines of code.
this.yourButtonName.MouseLeave += new System.EventHandler(this.demoButton_MouseLeave);
this.yourButtonName.MouseHover += new System.EventHandler(this.demoButton_MouseHover);
I have a ListView with the View set to LargeIcon.
I specifically need to detect when multiple items were selected by dragging a selection box around them with the mouse.
(For example I don't want to know when items were selected by CTRL + Click)
I thought I could simply do it by keeping track of whether the mouse was down while it was moving which would indicate dragging, then on mouse up if it was a drag then I can set another variable to indicate this.
In my example below mouseDown is set to true, but when I keep the mouse down and move it isDrag is never set to true and I can't see what I'm doing wrong.
(Edit: isDrag becomes true if I remove the if clause which is weird because as I said mouseDown is definitely true).
I realise the code is a little longer than it needs to be but it's for clarity.
bool mouseDown;
bool isDrag;
bool wasDrag;
private void listView1_MouseDown(object sender, MouseEventArgs args)
{
wasDrag = false;
mouseDown = true;
}
private void listView1_MouseMove(object sender, MouseEventArgs args)
{
if (mouseDown)
isDrag = true; // <-- Never becomes true, even though mouseDown is true
}
private void listView1_MouseUp(object sender, MouseEventArgs args)
{
if (isDrag)
wasDrag = true;
mouseDown = false;
isDrag = false;
}
I know it'll be something stupid. Please put me out of my misery.
Alternatively if someone knows of a better was to detect a dragging selection (what's the proper term?) then I'm all ears.
Can you try this:
private void listView1_MouseMove(object sender, MouseEventArgs args)
{
isDrag = mouseDown;
}
I think for some reason, your event listView1_MouseUp still fires, which makes your isDrag variable set to other than the intended value. Try to put breakpoints on both MouseMove and MouseUp events to see the sequence with which they are firing.
After further investigation I've discovered that for a ListView control the MouseMove event will not fire while MouseDown is still occurring and fires immediately after releasing the mouse.
I can only assume that the logic built into this control that allows you to select multiple files by dragging a selection is messing with these events and essentially making them synchronous.
I've put together a basic workaround for this. It's not ideal but it does the job so I thought I'd share.
Basically when the mouse goes down I record the position. When the mouse goes up I check to see if it has moved more than a certain distance in any direction. If it has not I consider it a click, if it has I consider it a drag.
// Records the mouse position on mousedown
int beforeMoveX;
int beforeMoveY;
// How far in pixels the mouse must move in any direction
// before we consider this a drag rather than a click
int moveBounds = 20;
private void listView1_MouseDown(object sender, MouseEventArgs e)
{
// Save the mouse position
beforeMoveX = e.X;
beforeMoveY= e.Y;
}
private void listView1_MouseUp(object sender, MouseEventArgs e)
{
// Did we move more than the bounds in any direction?
if (e.X < (beforeMoveX - moveBounds) ||
e.X > (beforeMoveX + moveBounds) ||
e.Y < (beforeMoveY - moveBounds) ||
e.Y > (beforeMoveY + moveBounds))
{
// DRAGGED!
}
else
{
// NOT DRAGGED!
}
}
Intro
I have a WPF application.
When i click/double click on a button to show next screen, this is captured with both MouseLeftButtonDown and MouseLeftButtonUp.
- MouseLeftButtonDown is making the button darker
- MouseLeftButtonUp is sending me to next screen
The problem:
If i "spam" or sometimes just click 2-3 (we say 3 times in this case) times on the button, it's start loading the next screen. When the next screen is shown, two mouse clicks is left in the queue and if the mouse is over another new button at the second screen, this is clicked on.
I tried with stuff like:
void LayoutRoot_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
Mouse.OverrideCursor = Cursors.Wait;
if (this.IsVisible && this.IsLoaded)
OnButtonPatient();
}
but both properties is set to true.
I guess thats right since i can see the button when the mouse event triggers.
The events can be explained like:
3 mouse clicks
mouse cursor = waiting cursor
next screen is loaded
mouse cursor = normal
mouse cursor = waiting cursor
next button is clicked
How can i handle this?
I dont want mouse event that happend on a previously screen follow on to my next screen.
Greetings!
I tried a simple example using StackPanel as control. Although I am not sure why you are not using Button Click event if you are using a button (Why move on ButtonUp?)
private int count = 0;
private void StackPanel_OnMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
if (count == 0 && (sender as StackPanel).IsMouseOver)
{
Mouse.OverrideCursor = Cursors.Wait;
count++;
}
e.Handled = true;
}
private void StackPanel_OnMouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
if (count == 1 && (sender as StackPanel).IsMouseOver)
{
Mouse.OverrideCursor = Cursors.Arrow;
count++;
}
e.Handled = true;
}
I would suggest checking the IsMouseOver property on your first window/screen when the MouseUp event fires. This would let you filter out events where the new window is blocking the first.
void LayoutRoot_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
Mouse.OverrideCursor = Cursors.Wait;
if (this.IsVisible && this.IsLoaded && this.IsMouseOver)
OnButtonPatient();
}
I'm remaking windows Minesweeper (from XP) and something they had included was that if you click a number with as many flags as it's number with the left and right mouse button at the same time, it reveals every other hidden tile around that number.
I'm having a hard time telling when both the Left and Right mouse buttons are pressed at the exact same time... I'm using a pair of bools, one for each button with the OnMouseDown and OnMouseUp events but if the 2 buttons are clicked at the exact same time (or really close), then only one MouseDown event goes off and the other does not... If you click and hold one of the buttons then click and hold the other, the code works though.
Is there a better way to detect this kind of "dual" click?
Edit:
Alright, small story for why I messed this up (it worked all along).
I have a macbook pro running Windows 7. For those of you who don't know, the macbook pro has a single bar for a mouse button that normally left clicks, but if you place 2 fingers down it right clicks, so you can't do both (and no way to middle click). So I was building my app and sending it to my friend, he was telling me it wasn't working, so I posted this question. I finally decided to try it on my other laptop, a Dell XPS with 2 mouse buttons... Once it worked there I passed it along to other friends and they confirmed it worked. I don't know how my first friend messed it up, but moral of the story is don't buy anything Apple. At least that's the moral I got.
Create a class boolean variable for the left and right button defaulted to false. When the mouse down event fires set the variable to true and check if both are true. When the mouse up fires set the variable to false.
public bool m_right = false;
public bool m_left = false;
private void MainForm_MouseDown(object sender, MouseEventArgs e)
{
m_objGraphics.Clear(SystemColors.Control);
if (e.Button == MouseButtons.Left)
m_left = true;
if (e.Button == MouseButtons.Right)
m_right = true;
if (m_left == false || m_right == false) return;
//do something here
}
private void MainForm_MouseUp(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
m_left = false;
if (e.Button == MouseButtons.Right)
m_right = false;
}
Complete Code:
private void Form1_MouseDown(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left) leftPressed = true;
else if (e.Button == MouseButtons.Right) rightPressed = true;
if (leftPressed && rightPressed)
{
MessageBox.Show("Hello");
// note:
// the following are needed if you show a modal window on mousedown,
// the modal window somehow "eats" the mouseup event,
// hence not triggering the MouseUp event below
leftPressed = false;
rightPressed = false;
}
}
private void Form1_MouseUp(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left) leftPressed = false;
else if (e.Button == MouseButtons.Right) rightPressed = false;
}
Another option is to use the static MouseButtons on the System.Windows.Forms.Control class
This will tell you which mouse buttons are currently pressed so that you can do something like the following:
((Control.MouseButtons & MouseButtons.Right) == MouseButtons.Right) &&
((Control.MouseButtons & MouseButtons.Left) == MouseButtons.Left)
You can also check out the MSDN example
I got the following code to work in my Click Event.
if ((Control.MouseButtons == MouseButtons.Right) || (Control.MouseButtons == MouseButtons.Left))
When only one mouse button is being pressed the "Control.MouseButton" assumes the value of "MouseButtons.None"
But when both the left and right mouse buttons are being pressed the "Control.MouseButton" assumes the value of either "MouseButtons.Right" or "MouseButtons.Left" according to which was pressed first / last (depending on how long time it was between the left and right button being pressed)
Try this,
Private Sub Form_Click(... , ByVal e As ystem.Windows.Forms.MouseEventArgs)
If e.Button = MouseButtons.Right And e.Button = MouseButtons.Left Then
MsgBox ('Right & Left code')
End If
Kind of an old question, but I came across this (coincidentally also while doing a Minesweeper clone) and felt it was missing something. If you want to have the two-button click but still catch regular single-button clicks as well, you can do the following:
private bool left_down;
private bool right_down;
private bool both_click;
private void Form1_MouseDown(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
left_down = true;
if (right_down)
both_click = true;
}
if (e.Button == MouseButtons.Right)
{
right_down = true;
if (left_down)
both_click = true;
}
}
private void Form1_MouseUp(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
if (!right_down)
{
if (both_click)
//Do both-click stuff here
else
//Do left-click stuff here
both_click = false;
}
left_down = false;
}
if (e.Button == MouseButtons.Right)
{
if (!left_down)
{
if (both_click)
//Do both-click stuff here
else
//Do right-click stuff here
both_click = false;
}
right_down = false;
}
}
It moves the detection to the mouse-up rather than the mouse-down. It doesn't do anything until you release both buttons. This works almost exactly like the Windows 7 version of Minesweeper, except that the right button alone in the original operates on mouse-down. (I honestly prefer my version). There's a bit of redundancy in that the both-click case is called in two places depending on whether you release the left or right button first, but this should probably be a single-line function-call anyhow. Bonus: You can check the both_click flag from elsewhere in order to draw the hint-square around your cursor showing which squares will be revealed when you release the buttons.
I want to create a card playing game. I the use mousemove event to drag cards through the window. The problem is if I move the mouse over another card, it is stuck because the card underneath the mouse cursor gets the mouse events, so that the MouseMove event of the window isn't fired.
This is what I do:
private void RommeeGUI_MouseMove(object sender, MouseEventArgs e)
{
if (handkarte != null)
{
handkarte.Location = this.PointToClient(Cursor.Position);
}
}
I tried the following, but there was no difference:
SetStyle(ControlStyles.UserMouse,true);
SetStyle(ControlStyles.EnableNotifyMessage, true);
Iam looking for a way to implement an application-global event-handler or a way to implement so called event-bubbling. At least I want to make the mouse ignore certain controls.
In order to do this you will need to keep track of a few things in your code:
On which card the mouse is pointing
when the mouse button is pressed;
this is the card that you want to
move (use the MouseDown event)
Move the the card when the mouse is moved
Stop moving the card when the mouse button is released (use the
MouseUp event)
In order to just move around controls, there is no need to actually capture the mouse.
A quick example (using Panel controls as "cards"):
Panel _currentlyMovingCard = null;
Point _moveOrigin = Point.Empty;
private void Card_MouseDown(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
_currentlyMovingCard = (Panel)sender;
_moveOrigin = e.Location;
}
}
private void Card_MouseMove(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left && _currentlyMovingCard != null)
{
// move the _currentlyMovingCard control
_currentlyMovingCard.Location = new Point(
_currentlyMovingCard.Left - _moveOrigin.X + e.X,
_currentlyMovingCard.Top - _moveOrigin.Y + e.Y);
}
}
private void Card_MouseUp(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left && _currentlyMovingCard != null)
{
_currentlyMovingCard = null;
}
}
What you could do, is send the MouseDown event to the event.function you want to call.
Say you got a "Label" ontop of a "Card", but you wan't to "go-through" it:
private void Label_MouseDown( object sender, MouseEventArgs)
{
// Send this event down the line!
Card_MouseDown(sender, e); // Call the card's MouseDown event function
}
Now the appropriate event-function is called, even though the bothersome label was clicked.
Normally you do this by, before capturing the mouse, seeing if anybody else has it...