Calling events for n buttons on the form - c#

In my previus post I asked how to create a set of n draggable buttons, which worked fine, but I'm now working on the following:
I placed an image on the form, and loaded a coordinate matrix, so that when I also drag the image, the buttons "follow the image", I'm trying to acomplish it by calling an event when the button is finished being dragged, calling an event and transforming "image coordinates" to "form coordinates". It works fine for just one, but the problem arises when I place n buttons, since I don't know how to "recognize" which button called the event, I'll show you how I did my stuff:
int x, y;
//Creates a set of four buttons with an icon
for (int i = 0; i < 4; i++)
{
x = rnd.Next(1, this.Width - 30);
y = rnd.Next(1, this.Height - 30);
botonCustom newboton = new botonCustom(32, 32, new Point(x, y), imageList1);
//New event for each button (Is it ok to do?)
//I tried to call the same function newboton_Move, since i do not know how to create an event for each button
newboton.Move += new EventHandler(newboton_Move);
//Name the button and writes it on a lablel
newboton.Description = EtiDiamond[i];
DiamondButton.Add(newboton);
this.Controls.Add(newboton);
}
Here is the function being called:
private void newboton_Move(object sender, EventArgs e)
{
// Here i use the coordinates transform method, i won't place the code because
// its too big and it goes against the rules :P, i think if i could somehow know which button called this...
}
Thanks for reading this

sender is the button that raised the event
var myButton = sender as Button;

Related

How can I change the color of a button each time I try to click on it?

I have a question recording to the code I wrote today. I know that I can change the backgroundcolor of the button, but just once (with: button2.BackColor = Color.Yellow;). But now, I have a problem.
The color should change each time I try to click on the button. How does it work? Thank you for your help.
This is my code. I programmed something funny: when you try to click the button, it disappears and appears elsewhere :).
ยจ
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
Random cox = new Random();
private void button2_MouseMove(object sender, MouseEventArgs e)
{
int x = cox.Next(500);
int y = cox.Next(500);
button2.Left = x;
button2.Top = y;
}
}
Besically you have 2 options: Either keep an array of colors and choose a color randomly from that array on each click, or generate a random color on each click.
option 1:
// inside your form:
Color[] colors = new Color[] {Color.Yellow, Color.Green, Color.Red};
// inside the button click event handler:
button2.BackColor = colors[col.Next(0,colors.Length)];
option2:
// inside the button click event handler:
button2.BackColor = new Color(col.Next(0,256), col.Next(0,256), col.Next(0,256));
Of course, both options use the Random instance named col in the code you provided.

Fire an event simultaneously for multiple dynamic controls in c# winform

I have N number of dynamically added PictureBoxes in FlowLayoutPanel.
When I create them I attach event handlers to them. For example:
for(int i=0;i<x;i++) {
var pe= new PictureBox();
pe.MouseUp+=mouseup;
pe.MouseDown+=mouseDown;
pe.MouseMove+=mouseMove;
pe.Paint+=paint;
}
My goal is to fire those events for all picture boxes whenever I work with any one of them. For example, if I move one picturebox (1st/2nd/3rd/.../n ) all others will move automatically, if I zoom any box, others will zoom automatically. How can I fire events simultaneously for all pictureboxes when I work with anyone.
If I try for example:
void mouseWheel(object sender, MouseEventArgs e) {
var control=(PictureBox)sender;
var parent=control.parent;
var pictureBoxes=parent.ofType<PictureBox>();
foreach(pb in pictureBoxes) {
//do something
}
}
It only works for the picture box I am working with.
You need to call a method instead of raising the event.
Create some methods and put logic on the methods, then in the event handler, first extract information that you need, then call suitable method with parameters.
For example:
void pictureBox_MouseWheel(object sender, MouseEventArgs e)
{
//Some parameter that you extract from eventArgs or somewhere else
int zoomFactor = e.Delta;
//Call the method on your picture boxes
foreach (var p in pictureBoxes)
{
Zoom(p, zoomFactor);
}
}
//The method that contains logic of zoom on a picture box
public void Zoom(PictureBox p, int zoomFactor)
{
//It is just an example, not a real logic
p.SizeMode = PictureBoxSizeMode.Zoom;
p.Width += (zoomFactor * 10);
p.Height += (zoomFactor * 10);
}
I supposed you have added all your pictureboxes in a List<PictureBox> when you created them.
Also if you have added your picture boxes to a Controls collection of a control, for example theControl, then you can find them later this way:
var pictureBoxes = theControl.Controls.OfType<PictureBox>().ToList();
It looks like you already have a list of picture boxes. So, try modifying your functions (for example your Zoom function) to work for all picture boxes in the list, rather than just the one picture box.
In other words, don't try to call the event handler for each picture box, make each event handler call a function, which modifies all picture boxes.

Handling an array of buttons

I'm creating a simple game where a melody is played, and buttons that corresponds to notes are supposed to be highlighted.
Then the user is to push the button, and during each click the buttons are to highlighted again. I would like to place all the buttons in the GUI graphically.
Can I add a highLight method to the buttons in the GUI? I know I probably could create a new class that ineherits from some button class and create the buttons in the code but I would prefer to do it graphically.
What is the neatest way to handle the button outputs? I know I could paste in code for each button like
private void button_withIndexA(object sender, EventArgs e)
{
checkIfThisNoteWasCorrect();
highLightThisButton();
setHighLightOffForAllOtherButtons();
}
However, I think it would be neater to collect all buttons in some sort of container class and make a function like
class buttonArrayHandler
{
/*constructors etc*/
private void someButtonWasClicked(object sender)
{
/*Check which button was clicked, and do stuff accordingly*/
}
}
However I don't know how to do that. Suggestions?
You could change the button colors to create a highlight effect, but if it's a game you can use images / graphics for buttons, and swap them to another graphic when clicked.
When you double click on a button / graphic / control, by default it creates a method and links it to the click action for you. Instead click on each control, then the little lightning icon, and under the click action, pick the same method for all of them.
Then in your method cast the object sender to get the original control, for example:
var clickedButton = (Button)sender;
Where (Button) may be (Graphics) or whatever type of control you used as a button.
EDIT:
If you need to access a group of controls, you can either keep a global list of names at the top of the form and loop through them:
public List<string> buttonList = new List<string>() { "button1", "button2" };
void SomeMethod()
{
foreach (var controlName in buttonList)
{
this.Controls[controlName].Text = "TEST";
}
}
Or use a fixed name and number range:
void SomeMethod()
{
for (int i = 1; i <= 2; i++)
{
this.Controls["button" + i].Text = "TEST";
}
}
I would recommend adding the buttons programatically just like Carlos487 mentioned, here is the code segment that I made and could work to your advantage:
public Form1()
{
InitializeComponent();
int topMod = 0;
for (int i = 0; i < 5; i++)
{
MakeButton(i,topMod);
topMod += 20;
}
}
public void MakeButton(int index, int margin)
{
Button currentButton = new Button();
currentButton.Text = "Note" + index;
currentButton.Top += margin;
currentButton.Click += OnButtonClick;
panel1.Controls.Add(currentButton);
}
public void OnButtonClick(object sender, EventArgs e)
{
//checkIfThisNoteWasCorrect();
//highLightThisButton();
//setHighLightOffForAllOtherButtons();
MessageBox.Show("My Action was activated!");
}
As you can see you can place the common functions within the OnButtonClick method like I did here, giving all of the buttons the same event sequence. If you do not want to go through the whole process of programming buttons then you could also just do this:
currentButton.Click += OnButtonClick;

Visual Studio 2010 TableLayoutPanel with Buttons events

I've made in Visual Studio 2010 in designer mode a TableLayoutPanel (for example 8x8 rowsxcolumns), then I've put in each field of this "matrix" a button. Is there any way how to handle the events centrally? I found that TableLayoutPanel have TabIndexChanged, but I don't know if this will be useful for me.
I'm just trying to find out if is possible this:
I click on second button and get the information on what button I've clicked and will be able to change some of his property - for example icon, or text.
Lets imagine an idea that I will understand tablelayoutpanel as an "matrix" or "array" and I want to work with it something like this:
1)I'll click on button on possition i (or i,j)
2)I'll change the Icon of button on possition i (or i,j)
Is that possible? If yes, how?
Thx
You can have a single method handle all your button click events and then use the sender parameter to modify the image on the button.
e.g.
private void CreateButtons(object sender, EventArgs e)
{
for (int i = 0; 8 < length; i++)
{
for (int j = 0; 8 < length; i++)
{
var btn = new Button() { Text = "Something" };
btn.Click += new EventHandler(btn_Click);
this.tableLayoutPanel1.Controls.Add(btn, i, j);
}
}
}
void btn_Click(object sender, EventArgs e)
{
((Button)sender).Image= SomeMethodThatReturnsAnImage();
}
As an aside the TabIndexChanged would be completely useless to you since its only raised when the TabIndex property of a control gets changed which is typically very rare. You'll rember that the TabIndex property is used to control the order of controls for when the user presses the Tab key.
Sounds like you just need to associate the click event of all your buttons with a single event handler, and then manipulate the clicked button, etc., inside the event handler

C# Dynamic Form Help

I'm trying to make something of a Tile-Map editor in C# using picture-boxes (the simplest way i could think to throw tiles into a form)
The code that Generates the picture boxes is:
public void Generate_Tiles(int width, int height)
{
for (int x = 0; x < width; x++)
{
for (int y = 0; y < height; y++)
{
System.Windows.Forms.PictureBox picturebox = new PictureBox();
picturebox.BackColor = SystemColors.ActiveCaption;
picturebox.Cursor = Cursors.Cross;
picturebox.Location = new System.Drawing.Point((x*32) + 4, (y*32) + 4);
picturebox.Name = x+y+"tile";
picturebox.Size = new System.Drawing.Size(32, 32);
picturebox.TabIndex = 0;
picturebox.TabStop = false;
picturebox.Click += new System.EventHandler(TileBox_Clicked));
map.Controls.Add(picturebox);
}
}
MessageBox.Show("Done");
}
That part works, as long as i use a small number of picture boxes at a time (8 by 8 seems to be the maximum that it wants to display in a decent amount of time)
I want to perform some action when the user clicks on a specified picture-box, which is why i have a onclick method, that's where i run into problems, all the picture-boxes are called... picture-box. As far as i can tell, there's no way for me to tell which picture-box the user clicked.
I will probably need to remake the way the dynamic form works anyway, since i cant get very many picture boxes, but I think the main problem will still be there, as long as i want it to be dynamic (which i do), not all of the tile-maps will be the same size.
Ive never done anything like this, and I've looked for ways to override the onclick event... which i couldn't find, and i couldn't find a good tile-engine that's up to date to use (except for XNA, but that's a little over the top for a simple tile-editor, i think)
Im likely going in the opposite direction then what i need to be doing.
The sender in your event handler will be the PictureBox which was clicked.
void TileBox_Clicked(object sender, EventArgs e)
{
PictureBox pictureBox = sender as PictureBox;
if(pictureBox != null)
{
//do stuff with your pictureBox
}
}
Can't you just cast the sender object to a PictureBox in your event handler, and work with that?
The first parameter in your event handler is the clicked control (which will be the PictureBox.
private void pictureBox1_Click(object sender, System.EventArgs e)
{
PictureBox pb = (PictureBox)sender;
// ...
}
I've taken this approach with a map tile editor as well. As others have said, you can use the sender parameter and cast it to a PictureBox to get the PictureBox object that was clicked. But I think you'll find (you probably already have) that a decent map size will really slow things down.
You might reconsider XNA. It seems complicated, and it's not as easy to get something working as just generating a bunch of PictureBox objects. But it's fast, and it's you can get a 2D map being displayed fairly quickly. You can also extend it easier, for example if you want your map to have different editable layers (terrain, etc.).
There are actually lots of ways to do this. I think the easiest is to use the sender of your event handler, which will point you back to the clicked button:
private void PictureBox_Click(object sender, EventArgs e)
{
var box = sender as PictureBox;
if (box != null)
{
//...
You can also create and add event handlers dynamically, which is an interesting option:
//...
for (int x = 0; x < width; x++)
{
for (int y = 0; y < height; y++)
{
System.Windows.Forms.PictureBox picturebox = new PictureBox();
pictureBox.Click += new Action<object, EventArgs>(
(sender, e) => { doStuff(pictureBox); }
);
In the above code, doStuff gets pictureBox as a parameter, so it knows which object it's supposed to work on.

Categories

Resources