How to move a new (custom) button at run time? - c#

I have a problem with my winforms C# project.
I want to move a new (custom) button around the form (at run time).
How can I do that?
Button[] buttons = new Button[1000];
int counter = 0;
Button myText = new Button();
private void button2_Click(object sender, EventArgs e)
{
Button myText = new Button();
myText.Tag = counter;
myText.Location = new Point(x2,y2);
myText.Text = Convert.ToString(textBox3.Text);
this.Controls.Add(myText);
myText.MouseMove += new MouseEventHandler(myText_MouseMove);
myText.MouseDown += new MouseEventHandler(myText_MouseDown);
buttons[counter] = myText;
counter++;
}
public void myText_MouseMove(object sender, MouseEventArgs e)
{
int s = e.GetHashCode();
int check = 0;
for (int i = 0; i < counter; i++)
{
if (buttons[i].GetHashCode() == s)
check = i;
}
if (e.Button == MouseButtons.Left)
{
buttons[check].Left += e.X - move.X;
buttons[check].Top += e.Y - move.Y;
}
}
void myText_MouseDown(object sender, MouseEventArgs e)
{
move = e.Location;
}
I use the code above to create the new button and I am trying to move it around the form.
If I code for just 1 button I am able to move it but, I want to be able to do this for more buttons as well.

Try this
public void myText_MouseMove(object sender, MouseEventArgs e)
{
Button button = (Button)sender;
if (e.Button == MouseButtons.Left)
{
button .Left += e.X - move.X;
button .Top += e.Y - move.Y;
}
}

I've come across this thread while doing something similar.
Even though the thread is quite old; I'm sharing the way I've achieved this.
Notes:
Unlike the operator question above; in the example bellow; I'm not using a Button[] (array) with 1000 buttons; (but this can be easily changed).
In the example bellow I have:
A Form with 1 Button on it.
When this button is clicked; it will create a new (Custom) Button
(hence; having two button click events in the code simply for the test purpose).
Bellow you can find: A way to generate the button; and so how to drag it around the form.
/* Variables */
// Used to Store the Mouse Location on the Screen when Button is Clicked
private Point mouseDownLocation;
// Used to know if the Button can be Moved.
private bool isMoveable = false;
// Used to prevent clicking the button when being dragged
private bool clickEnabled = true;
/// <summary> Occurrs when the visible button on the Form is clicked. </summary>
private void Button_Click(object sender, EventArgs e)
{
// Create a variable to set the Size of the new Button.
Size size = new Size(100, 100);
// Create the Button. Specifying the Button Text and its Size.
CreateButton("Button Text", size);
}
/* Custom Button : Create & Configure the Button */
private void CreateButton(string btnText, Size btnSize)
{
// Create the Button instance:
Button btn = new Button();
// Custom Button Style Configuration Code.
// i.e: FlatStyle; FlatAppearance; BackColor; ForeColor; Text; Size; Location; etc...
btn.FlatStyle = FlatStyle.Standard;
btn.FlatAppearance.BorderColor = Color.White;
btn.BackColor = Color.Purple;
btn.ForeColor = Color.White;
btn.Text = btnText;
btn.Size = btnSize;
btn.Location = new Point(100, 100);
// Custom Button Event.
btn.Click += new EventHandler(CustomButton_Click);
btn.MouseDown += new MouseEventHandler(CustomButton_MouseDown);
btn.MouseMove += new MouseEventHandler(CustomButton_MouseMove);
btn.MouseUp += new MouseEventHandler(CustomButton_MouseUp);
// Add Button to Control Collection.
Controls.Add(btn);
// Show Button.
btn.Show();
}
/* Custom Button Events */
/// <summary> Occurrs whenever the Custom Button is Clicked </summary>
private void CustomButton_Click(object sender, EventArgs e)
{
if (clickEnabled)
{
// Note: The "for" loop bellow lets you get the current button; so you can drag it.
Button btn = (Button)sender;
// Iterate over the Form Controls
for (int i = 0; i < Controls.Count; i++)
{
// If the Button Clicked Corresponds to a Found Index in Control Collection...
if (i == Controls.IndexOf(btn))
{
// Perform Corresponding Button Action.
MessageBox.Show(btn.Name + " Clicked!");
}
}
}
}
/// <summary> Occurrs whenever Left Mouse Button Clicks the Button and is Kept Down. </summary>
private void CustomButton_MouseDown(object sender, MouseEventArgs e)
{
// Check if Left Mouse Button is Clicked.
if (e.Button == MouseButtons.Left)
{
// Set mouseDownLocation (Point) variable, according to the current mouse location (X and Y).
mouseDownLocation = e.Location;
// Enable the hability to move the Button.
isMoveable = true;
}
}
/// <summary> Occurrs whenever Left Mouse Button is Down and Mouse is Moving the Button. </summary>
private void CustomButton_MouseMove(object sender, MouseEventArgs e)
{
Button btn = (Button)sender;
// If the hability to move the button is "true" and the mouse button used to drag the button is the left mouse button:
if (isMoveable)
{
if (e.Button == MouseButtons.Left)
{
// Set the Button location X and Y...
btn.Left = e.X + btn.Left - mouseDownLocation.X;
btn.Top = e.Y + btn.Top - mouseDownLocation.Y;
}
}
// Disable Click hability (See: Note at the end of this post).
clickEnabled = false;
}
/// <summary> Occurrs whenever Left Mouse Button is not longer being hold down (Left Mouse Button is Up). </summary>
private void CustomButton_MouseUp(object sender, MouseEventArgs e)
{
// Disables the hability to move the button
isMoveable = false;
clickEnabled = true;
}
Note: The Custom Button Click interferes with the MouseDown Event. In a "simple" manner:
I updated the code by including a boolean value to prevent clicking the button when actually it is being dragged.
Hope this helps you out understanding how to accomplish this feature.
Hope this helps people out achieving this goal.

Related

Dynamic button click event within a timer tick event

I have a grid with 9 buttons. In the timer tick event a random button is higlighted. If one clicks the higlighted button, a dynamic click event is created and within the click event the button is marked with a different color. The counterHits variable in the dynamic button click event is supposed to keep track of the highlighted buttons that were hit. Sometimes though it increases the variable more than by one. I cannot figure out why this is happening. Any help anyone?
public partial class Form1 : Form
{
const int buttons = 9;
int counterHits;
int counterTicks;
int currentIndex;
int lastIndex;
bool hit = false;
Random r;
Timer timerGameLoop;
Timer timerUpdateUI;
public Form1()
{
InitializeComponent();
timerGameLoop = new Timer();
timerGameLoop.Interval = 1000;
timerGameLoop.Tick += t_Tick;
timerUpdateUI = new Timer();
timerUpdateUI.Interval = 10;
timerUpdateUI.Tick += timerUpdateUI_Tick;
r = new Random();
}
// set up the grid and start
private void btnStart_Click(object sender, EventArgs e)
{
for (int i = 0; i < buttons; i++)
{
var b = new Button();
b.Size = new Size(100, 100);
b.Margin = new Padding(0);
b.BackColor = Color.White;
flowLayoutPanel.Controls.Add(b);
}
timerGameLoop.Start();
timerUpdateUI.Start();
}
// tick event ui update loop
void timerUpdateUI_Tick(object sender, EventArgs e)
{
lblHitCounter.Text = "hits : " + counterHits.ToString();
lblTickCounter.Text = "ticks : " + counterTicks.ToString();
}
// tick event game loop
void t_Tick(object sender, EventArgs e)
{
// reset to white background if not clicked
if (!hit)
flowLayoutPanel.Controls[lastIndex].BackColor = Color.White;
// highlight button to be clicked
currentIndex = r.Next(buttons);
lastIndex = currentIndex;
flowLayoutPanel.Controls[currentIndex].BackColor = Color.Violet;
// highligted button clicked
flowLayoutPanel.Controls[currentIndex].Click += b_Click;
hit = false;
counterTicks++;
}
// highlighted button clicked event
void b_Click(object sender, EventArgs e)
{
var b = (Button)sender;
b.BackColor = Color.Olive;
hit = true;
counterHits++;
b.Click -= b_Click;
}
}
The following lines attaches b_Click to your button. That eventhandler is only removed if you press the button
flowLayoutPanel.Controls[currentIndex].Click += b_Click;
See the implementation of b_Click
// highlighted button clicked event
void b_Click(object sender, EventArgs e)
{
//Stugg
b.Click -= b_Click;←Removed Here only if it is pressed
}
This line indicates that some buttons have more than one EventHandler attached. Therefore when you click the button eventhandler runs more than once.

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.

Removing dynamically generated buttons

I'm working with C# windows forms and need some help. I have a button that creates other buttons and adds them to the list 'buttons'. I need to have each button created destroy itself when it is clicked.
//create new button
Button newButton = new Button();
newButton.Name = "aButt"+buttNum;
Debug.WriteLine(newButton.Name);
buttNum++;
newButton.Text = "Button!";
newButton.Height = 50;
newButton.Width = 50;
//controls where the new button gets placed
if (curX > 9)
{
curX = 0;
curY++;
//defines the point the button spawns
newButton.Location = new System.Drawing.Point((curX * 55)+10, curY * 55);
//increments X to avoid placing a button on top of another
curX++;
}
else
{
newButton.Location = new System.Drawing.Point((curX * 55) + 10, curY * 55);
curX++;
}
newButton.UseVisualStyleBackColor = true;
newButton.Click += new System.EventHandler(this.removeThisButton);
buttons.Add(newButton);
this.Controls.Add(newButton);
I have the event listener set up, but since the sender has no actual information on the button itself i'm not sure how to get rid of it.
Any help is appreciated!
The click event handler has the signature
private void myButton_Click(object sender, EventArgs e)
The object sender is the source of the event. Just cast that to a Button, and there's what got clicked:
Button whatWasClicked = sender as Button;
if(whatWasClicked == null)
// never mind -- it wasn't a button...
Sender is the button. You can remove it from Form's control collection like this:
private void removeThisButton(object sender, EventArgs e) {
this.Controls.Remove(sender);
}

Capture the right button click event

I'm playing around abit with winforms and its controls and just discovered how to do custommade buttonclicks. However, there is a problem. I've got a loop, that's looping through a list of elements, and if a condition appears - I'm creating a button that will pop up a gridview.
public void draw(ref Panel inputPanel) //draws the eventline
{
int stepCounter = 0;
for (int i = 0; i < DaysList.Count-1; i++)
{
Button b1;
if (DaysList[i].Elements.Count > max)
{
b1 = new Button(); //Create the box
b1.Width = 120;
b1.Height = 40; //Set width and height
b1.Location = new Point(stepCounter + 35, 70); //Location
inputPanel.Controls.Add(b1); //
b1.Text = "Check event date in grid";
b1.Show();
b1.BringToFront();
b1.Click += new EventHandler((sender, e) => btn_Click(sender, e, DaysList[i].Elements));
stepCounter += 200;
}
}
}
That was my method for creating the buttons and a click event for the when my condition appears. The function that is passed to the eventhandler looks like this:
public void btn_Click(object sender, EventArgs e, List<EventElement> inputElems)
{
Button button = sender as Button;
DataGridForm window = new DataGridForm(inputElems);
window.Show();
}
public class EventElement
{
public EventElement()
{
}
public int Count{get;set;}
public string Date{get;set;}
}
The clickpart of the event is fine but whenever i click the spawned buttons, I get the wrong data into the gridview. As an example: The loop has created four buttons for me and they are presented on a straight line on the form. But whenever i click one of the buttons - dosnt matter which one of them, the button always return the data of the last spawned button. A more clear example: lets say we have the list inputElems looks like this:
inputElems[0].Count -> 2644
inputElems[1].Count -> 2131
inputElems[2].Count -> 8467
inputElems[3].Count -> 5462
When i now click the second button, the input to the second buttons parameter list should have the values (sender, e, 2131), right? but for some reason, the last argument gets the same like the 4th element in the list, even though i call the secondly created button.
I figured that it has something to do with me always calling the last added button_click to the eventhandler of the button, if so, how do I call different clicks from the EventHandler?
Instead of passing inputElems with the EventHandler, you can use Tag.
E.g. use:
b1.Tag=i;
Then in your click event handler:
public void btn_Click(object sender, EventArgs e)
{
Button button = sender as Button;
DataGridForm window = new DataGridForm(DaysList[int.Parse(button.Tag.ToString())].Elements);
window.Show();
}
The problem is that the for loop is out of scope, and thus unable to provide you with the data you're looking for. A more straight forward approach might be something like this:
public void draw(ref Panel inputPanel) //draws the eventline
{
int stepCounter = 0;
for (int i = 0; i < DaysList.Count-1; i++)
{
Button b1;
if (DaysList[i].Elements.Count > max)
{
b1 = new Button(); //Create the box
b1.Width = 120;
b1.Height = 40; //Set width and height
b1.Location = new Point(stepCounter + 35, 70); //Location
inputPanel.Controls.Add(b1); //
b1.Text = "Check event date in grid";
b1.Show();
b1.BringToFront();
b1.Tag = DaysList[i].Elements;
b1.Click += btn_Click;
stepCounter += 200;
}
}
}
and then in btn_Click, do this:
public void btn_Click(object sender, EventArgs e)
{
Button button = sender as Button;
int inputElems = (List<EventElement>)button.Tag;
DataGridForm window = new DataGridForm(inputElems);
window.Show();
}

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;

Categories