Get Mouse State without access to MouseEventArgs? - c#

I have a form with many, many controls. I need to detect if the mouse is down or if it's up. Most of the time, I don't have MouseEventArgs.
Is there a quick and easy way to tell if the mouse is down without mouseEventArgs?
Is there an alternative, or is something like this the only way?:
foreach (Control c in this.Controls)
{
c.MouseUp += new MouseEventHandler(globalMouseUp);
c.MouseDown += new MouseEventHandler(globalMouseDown);
}
bool isMouseUp = true;
private void globalMouseDown(object sender, MouseEventArgs e)
{
isMouseUp = false;
}
private void globalMouseUp(object sender, MouseEventArgs e)
{
isMouseUp = true;
}

You can try checking with a timer:
private void timer1_Tick(object sender, EventArgs e) {
this.Text = "Mouse Is " + (Control.MouseButtons == MouseButtons.Left);
}

ChecK Control.MouseButtons static property:
if (Control.MouseButtons == MouseButtons.Left)
{
}

Related

Detect two buttons clicked for touchscreen

I have an application for kiosk machine that appears always on the top and fullscreen. Also, I have to turn off explorer.exe.
Therefore, I will not be able to access anything without a keyboard.
I'm thinking to make gestures or invincible buttons so that I can turn on explorer.exe without keyboard.
I would like to know if there is a way to detect if two buttons are clicked at the same time. I've tried using the following code but it is not working.
PS: I can't debug it line by line as my PC do not have touchscreen.
Therefore, I cannot find out which line causes the problem.
private bool button1WasClicked = false;
private bool button2WasClicked = false;
private void button1_MouseDown(object sender, MouseEventArgs e)
{
button1WasClicked = true;
}
private void button1_MouseUp(object sender, MouseEventArgs e)
{
button1WasClicked = false;
}
private void button2_MouseUp(object sender, MouseEventArgs e)
{
button2WasClicked = false;
}
private void button2_MouseDown(object sender, MouseEventArgs e)
{
if (button1WasClicked == true)
{
Process.Start(Path.Combine(Environment.GetEnvironmentVariable("windir"), "explorer.exe"));
Application.Exit();
button1WasClicked = false;
}
}
You can't click two buttons at once with a mouse or keyboard, and if you're talking about using a touchscreen, the WinForms framework doesn't support them (taps will simply be interpreted as individual mouse clicks at best). You'll want to look at using the Surface SDK or something else instead.
I've found a different solution where the buttons(panels) have to be clicked in a certain sequence to achieve what I wanted. I've also added a timer. Below is my code.
private bool panel1WasClicked = false;
private bool panel2WasClicked = false;
int second = 0;
private void panel1_Click(object sender, EventArgs e)
{
MaintenanceTimer.Interval = 500;
MaintenanceTimer.Start();
second = 0;
if (panel1WasClicked == false)
{
panel1WasClicked = true;
}
else
{
panel1WasClicked = false;
}
}
private void panel2_Click(object sender, EventArgs e)
{
if (panel2WasClicked == false && panel1WasClicked == true)
{
panel2WasClicked = true;
}
else
{
panel2WasClicked = false;
}
}
private void panel3_Click(object sender, EventArgs e)
{
if (panel1WasClicked && panel2WasClicked == true)
{
//Do something
}
panel1WasClicked = false;
panel2WasClicked = false;
MaintenanceTimer.Stop();
}
private void MaintenanceTimer_Tick(object sender, EventArgs e)
{
second += 1;
if (second >= 5)
{
MaintenanceTimer.Stop();
second = 0;
panel1WasClicked = false;
panel2WasClicked = false;
}
}

Drag and drop an to TextBox in a specific mouse position - Show caret or position indicator

I am pasting an item from a TreeView to a TextBox, but I want to paste that item in the mouse's current position and also show a caret like the image below.
Image with caret:
Here is my code:
private void tvOperador_ItemDrag(object sender, ItemDragEventArgs e)
{
var node = (TreeNode)e.Item;
if (node.Level > 0)
{
DoDragDrop(node.Text, DragDropEffects.Copy);
}
}
private void txtExpresion_DragEnter(object sender, DragEventArgs e)
{
if (e.Data.GetDataPresent(typeof(string))) e.Effect = DragDropEffects.Copy;
}
private void txtExpresion_DragDrop(object sender, DragEventArgs e)
{
if (e.Data.GetDataPresent(typeof(System.String)))
{
string Item = (System.String)e.Data.GetData(typeof(System.String));
string[] split = Item.Split(':');
txtExpresion.Text += split[1];
}
}
This is tricky as the Drag&Drop operation keeps the mouse captured, so you can't use the mouse events..
One way is to set up a Timer to do the work..:
Timer cursTimer = new Timer();
void cursTimer_Tick(object sender, EventArgs e)
{
int cp = txtExpresion.GetCharIndexFromPosition(
txtExpresion.PointToClient(Control.MousePosition));
txtExpresion.SelectionStart = cp;
txtExpresion.SelectionLength = 0;
txtExpresion.Refresh();
}
The Timer uses the Control.MousePosition function to determined the cursor position every 25ms or so, sets the caret and updates the TextBox.
In your events you initialize it and make sure the TextBox has focus; finally you add the string at the current selection:
private void txtExpresion_DragEnter(object sender, DragEventArgs e)
{
if (e.Data.GetDataPresent(typeof(string)))
{
e.Effect = DragDropEffects.Copy;
txtExpresion.Focus();
cursTimer = new Timer();
cursTimer.Interval = 25;
cursTimer.Tick += cursTimer_Tick;
cursTimer.Start();
}
}
private void txtExpresion_DragDrop(object sender, DragEventArgs e)
{
if (e.Data.GetDataPresent(typeof(System.String)))
{
cursTimer.Stop();
string Item = (System.String)e.Data.GetData(typeof(System.String));
string[] split = Item.Split(':');
txtExpresion.SelectedText = split[1]
}
}
A different way to solve it would be to not use normal Drag&Drop and only code the mouse events but this one worked ok a my first tests.
Update
While the above solution does work, using a Timer seems not exactly elegant. Much better to use the DragOver event, as seen in Reza's answer. But instead of painting a cursor, why not do the real thing, i.e. take control of the actual I-beam..?
The DragOver event is called all the time during the move so it works pretty much like MousMove would: So here is a merger of the two solutions, which I believe is the best way to do it:
private void txtExpresion_DragDrop(object sender, DragEventArgs e)
{
if (e.Data.GetDataPresent(typeof(System.String)))
{
string Item = (System.String)e.Data.GetData(typeof(System.String));
string[] split = Item.Split(':');
txtExpresion.SelectionLength = 0;
txtExpresion.SelectedText = split[1];
}
}
private void txtExpresion_DragEnter(object sender, DragEventArgs e)
{
if (e.Data.GetDataPresent(typeof(string)))
{
e.Effect = DragDropEffects.Copy;
txtExpresion.Focus();
}
}
private void txtExpresion_DragOver(object sender, DragEventArgs e)
{
int cp = txtExpresion.GetCharIndexFromPosition(
txtExpresion.PointToClient(Control.MousePosition));
txtExpresion.SelectionStart = cp;
txtExpresion.Refresh();
}
You can draw a caret over TextBox in DragOver event. Also set the SelectionStart to the char index you get from mouse position. Then in DragDrop event, just set SelectedText.
private void textBox1_DragOver(object sender, DragEventArgs e)
{
if (e.Data.GetDataPresent(typeof(System.String)))
{
var position = textBox1.PointToClient(Cursor.Position);
var index = textBox1.GetCharIndexFromPosition(position);
textBox1.SelectionStart = index;
textBox1.SelectionLength = 0;
textBox1.Refresh();
using (var g = textBox1.CreateGraphics())
{
var p = textBox1.GetPositionFromCharIndex(index);
g.DrawLine(Pens.Black, p.X, 0, p.X, textBox1.Height);
}
}
}
private void textBox1_DragDrop(object sender, DragEventArgs e)
{
if (e.Data.GetDataPresent(typeof(System.String)))
{
string txt = (System.String)e.Data.GetData(typeof(System.String));
textBox1.SelectedText = txt;
}
}

If one checkbox is checked, set the other to unchecked

I have two checkboxes on my form; chkBuried and chkAboveGround. I want to set it up so if one is checked, the other is unchecked. How can I do this?
I have tried the CheckChanged property:
private void chkBuried_CheckedChanged(object sender, EventArgs e)
{
chkAboveGround.Checked = false;
}
private void chkAboveGround_CheckedChanged(object sender, EventArgs e)
{
chkBuried.Checked = false;
}
And it works, just not as well as I hoped. That is, when I check chkBuried, then check chkAboveGround, both boxes become unchecked before I can check another one again.
modify your code as below.
private void chkBuried_CheckedChanged(object sender, EventArgs e)
{
chkAboveGround.Checked = !chkBuried.Checked;
}
private void chkAboveGround_CheckedChanged(object sender, EventArgs e)
{
chkBuried.Checked = !chkAboveGround.Checked;
}
I suggest you use check_click instead of check_changed
private void checkBox1_Click(object sender, EventArgs e)
{
checkBox2.Checked = false;
checkBox3.Checked = false;
}
private void checkBox2_Click(object sender, EventArgs e)
{
checkBox1.Checked = false;
checkBox3.Checked = false;
}
private void checkBox3_Click(object sender, EventArgs e)
{
checkBox1.Checked = false;
checkBox2.Checked = false;
}
The reason for the behavior you have explained is that you are using CheckedChanged event, which means that when you are setting the Checked property of a CheckBox manually, the event is also fired, causing another box to react again.
Therefore, the following might help you:
private void chkBuried_CheckedChanged(object sender, EventArgs e)
{
if (chkBuried.Checked == true) {
chkAboveGround.Checked = false;
} else {
chkAboveGround.Checked = true;
}
}
private void chkAboveGround_CheckedChanged(object sender, EventArgs e)
{
if (chkAboveGround.Checked == true) {
chkBuried.Checked = false;
} else {
chkBuried.Checked = true;
}
}
UPDATE 29.03.2020: functionally the code in my answer is the same as the answer given by Riz. Nevertheless, I am leaving the code as I put it originally since it might make the whole situation easier to understand for the people who are new to coding. If you are to implement anything similar in production code, please use the answer by Riz as an example.
I would prefer radio buttons, but you can do something like this:
public void CheckACheckBox(Checkbox ck)
{
foreach (Control ckb in this.Controls)
{
if ((ckb is CheckBox) && (ckb == ck))
ck.Checked = true;
else
ck.Checked = false;
}
}
List<CheckBox> groupOfCheckBoxes = new List<CheckBox>();
void InitFunction() {
groupOfCheckBoxes.Add(checkbox1);
groupOfCheckBoxes.Add(checkbox2);
groupOfCheckBoxes.Add(checkbox3);
foreach (CheckBox cb in groupOfCheckBoxes)
cb.Click += checkbox_Click
}
void checkbox_Click(object sender, EventArgs e)
{
foreach (CheckBox cb in groupOfCheckBoxes) {
cb.IsChecked = cb == sender;
}
}
However I would suggest radio boxes as well.
The code above is untested and may have some typos
Better version, allows the user to uncheck boxes.
private void chkOne_CheckedChanged(object sender, EventArgs e)
{
if (chkTwo.Checked == true)
{
chkTwo.Checked = !chkOne.Checked;
}
}
private void chkTwo_CheckedChanged(object sender, EventArgs e)
{
if (chkOne.Checked == true)
{
chkOne.Checked = !chkTwo.Checked;
}
}
The best option and easiest way for me was to create a Click event instead of a CheckedChanged event.
This method works perfectly with two or more checkbox and allows to have them all unchecked.
private void chkOne_Click(object sender, EventArgs e)
{
chkTwo.Checked = false;
}
private void chkTwo_Click(object sender, EventArgs e)
{
chkOne.Checked = false;
}
This will work for two unchecked boxes, since they are already unchecked it is simpler.
I had to do this myself also.
private void customer_IsCheckedChanged(object sender, EventArgs e)
{
business.IsChecked = false;
}
private void business_IsCheckedChanged(object sender, EventArgs e)
{
customer.IsChecked = false;
}
I needed to show or not show a table when activating the CheckBox, how they were two, if I activated both, everything was fine, but if I tried to deactivate one later, the other was also deactivated. PD: The default value for the tables that I used was Visible=false. The solution I got was the following:
protected void YourNameOfMethodForBothCheckBox(object sender, EventArgs e)
{
if (CheckBox_1.Checked == true)
{
Table_1.Visible = true;
if (CheckBox_2.Checked == true)
{
Table_2.Visible = true;
}
else { Table_2.Visible = false; }
}
else
{
Table_1.Visible = false;
if (CheckBox_2.Checked == false)
{
Table_2.Visible = false;
}
else
{
Table_2.Visible = true;
}
}
}

Making a panel draggable

I am creating a "cropping tool", and i need to make a panel that contains 2 buttons draggable.
Until now i've tried something like this, but the change location event happens only when i click the right button of the mouse...
this.MouseDown += new MouseEventHandler(onRightClickMouse);
private void onRightClickMouse(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Right)
{
Point localMouseClickPoint = new Point(e.X, e.Y);
panel1.Location = localMouseClickPoint;
}
}
My question: How can i make that panel draggable in my form?(I mean click on the panel then drag it to a location).
Try something like this:
delegate void updatePanelCallback();
panel1.MouseDown += new MouseEventHandler(onMouseDown);
panel1.MouseUp += new MouseEventHandler(onMouseUp);
System.Timers.Timer runTimer = new System.Timers.Timer(100);
runTimer.Elapsed += new ElapsedEventHandler(onTimerElapsed);
private void onMouseDown(object sender, MouseEventArgs e)
{
if (e.Button != MouseButtons.Right)
{
return;
}
runTimer.Enabled = false;
}
private void onMouseUp(object sender, MouseEventArgs e)
{
runTimer.Enabled = false;
}
public void updatePanelLocation()
{
if (this.InvokeRequired)
{
this.Invoke(new updatePanelCallback(updatePanelLocation), new object[] {});
}
else
{
Cursor curs = new Cursor(Cursor.Current.Handle);
panel1.Location = curs.Position;
}
}
private void onTimerElapsed(object source, ElapsedEventArgs e)
{
updatePanelLocation();
}
You could try something in two steps, preparing the action on MouseDown event and finishing it on MouseUp.

Simple button move

I have a card game application, and I want to create a simple animation that will make the button move when it is clicked and dragged.
I have tried:
bool _Down = false;
private void button1_MouseDown(object sender, MouseEventArgs e)
{
_Down = true;
}
private void button1_MouseUp(object sender, MouseEventArgs e)
{
_Down = false;
button1.Location = e.Location;
}
private void button1_MouseMove(object sender, MouseEventArgs e)
{
if (_Down)
{
button1.Location = e.Location;
}
}
This doesn't work either. The effect I get is that when the button is clicked and dragged, the button is not visible until the mouse is released, and also, the button doesn't actually stay at the location of the mouse.
I also tried:
bool _Down = false;
private void button1_MouseDown(object sender, MouseEventArgs e)
{
_Down = true;
}
private void button1_MouseUp(object sender, MouseEventArgs e)
{
_Down = false;
button1.Location = Cursor.Position;
}
private void button1_MouseMove(object sender, MouseEventArgs e)
{
if (_Down)
{
button1.Location = Cursor.Position;
}
}
This works better than the first one as the button is visible when dragged and stops at mouse position, but the only problem is that Cursor.Position returns the cursor position in relativeness to the screen, not the form therefore. The button doesn't actually move at the pace of the cursor.
What can I do to achieve what I want?
Moving Control at runtime is very easy:
Point downPoint;
private void button1_MouseDown(object sender, MouseEventArgs e)
{
downPoint = e.Location;
}
private void button1_MouseMove(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left) {
button1.Left += e.X - downPoint.X;
button1.Top += e.Y - downPoint.Y;
}
}
Try this
private void button1_MouseUp(object sender, MouseEventArgs e)
{
_Down = false;
button1.Location = PointToClient(Cursor.Position);
}
private void button1_MouseMove(object sender, MouseEventArgs e)
{
if (_Down)
{
button1.Location = PointToClient( Cursor.Position);
}
}

Categories