I am currently having trouble with my slide puzzle. The thing is that the codes work but only for the 9 buttons that appeared out of no where. Here is an image of it.
This is the code I used to run the program.
public partial class frmSlide : Form
{
/*
* frmSlide -constructor
*
*/
DateTime TimedSolved = DateTime.Now;
bool starting = false;
bool changed = false;
const int rows = 3;
const int cols = 3;
Button blkButton= new Button();
public Button[,] btnArray = new Button[rows, cols];
Button[,] buttons = new Button[3, 3];
public frmSlide()
{
InitializeComponent();
}
/*
* allNumberButton_Click - click event handler for allNumberButton
*
* Parameter: sender -who sent the event
* Parameter: e -info about the event
* Return: nothing
*/
private void frmSlide_Load(object sender, EventArgs e)
{
blkButton.Text = " ";
int curNum = 1;
for (int x = 0; x < rows; x++)
{
for (int y = 0; y < cols; y++)
{
Button b;
b = new Button();
b.Location = new Point(100 + (y * 50), 100 + (x * 50));
b.Height = 40;
b.Width = 40;
b.Text = curNum.ToString();
btnArray[x, y] = b;
b.TextAlign = ContentAlignment.MiddleCenter;
b.Font = new Font(FontFamily.GenericSerif, (float)15.0);
b.Click += new System.EventHandler(this.allNumberButton_Click);
this.Controls.Add(b);
curNum++;
}
}
btnArray[rows - 1, cols - 1].Text = "";
blkButton = btnArray[rows - 1, cols - 1];
blkButton.Text = " ";
}
private void allNumberButton_Click(object sender, EventArgs e)
{
{
Button clickedButton = sender as Button;
if (clickedButton.Text == "")
{
goto done;
}
Point clicked = clickedButton.Location;
int clickedX = clicked.X;
int clickedY = clicked.Y;
Point blank = blkButton.Location;
int blankX = blank.X;
int blankY = blank.Y;
int distanceX = Math.Abs(clickedX - blankX);
int distanceY = Math.Abs(clickedY - blankY);
changed = false;
if ((distanceX == 50 && distanceY == 0) ||
(distanceX == 0 && distanceY == 50))
{
changed = true;
string tmp = clickedButton.Text;
clickedButton.Text = "";
blkButton.Text = tmp;
blkButton = clickedButton;
}
if (changed == true)
{
if (btnArray[rows - 1, cols - 1].Text != "")
{
goto done;
}
int checkNum = 1;
for (int a = 0; a < rows; a++)
{
for (int b = 0; b < cols; b++)
{
if (a == rows - 1 && b == cols - 1)
{
goto done2;
}
if (btnArray[a, b].Text != checkNum.ToString())
{
goto done;
}
checkNum++;
}
}
done2:;
if (starting == false)
{
DateTime nowSolved = DateTime.Now;
TimeSpan lengthOfTime = nowSolved - TimedSolved;
double hours = lengthOfTime.TotalHours;
int hours2 = Convert.ToInt32(hours);
double minutes = lengthOfTime.TotalMinutes;
int minutes2 = Convert.ToInt32(minutes);
double seconds = lengthOfTime.TotalSeconds;
int seconds2 = Convert.ToInt32(seconds);
MessageBox.Show("Congratulations! \n \n It took you " + hours2 +
" hours " + minutes2 + " minutes " + seconds2 + " seconds \n \n"
+ " to solve it!");
}
else
{
return;
}
}
done:;
}
}
/*
* btnReset_Click - click event handler
* .text
* Parameter: sender -who sent the event
* Parameter: e -info about the event
* Return: nothing
*/
private void btnReset_Click(object sender, EventArgs e)
{
{
int reset = 1;
for (int c = 0; c < rows; c++)
{
for (int l = 0; l < cols; l++)
{
btnArray[c, l].Text = reset.ToString();
reset++;
btnArray[rows - 1, cols - 1].Text = "";
blkButton = btnArray[rows - 1, cols - 1];
}
}
}
}
/*
* btnExit_Click -click event handler
*
* Parameter: sender -who sent the event
* Parameter: e -info about the event
* Return: nothing
*/
private void btnExit_Click(object sender, EventArgs e)
{
this.Close();
}
/*
* frmSlide_Load- Load event handler
*
* Parameter: sender -who sent the event
* Parameter: e -info about the event
* Return: nothing
*/
private void btnStart_Click(object sender, EventArgs e)
{
starting = true;
Random rnd = new Random();
for (int z = 0; z < 100; z++)
{
int rndNumberX = rnd.Next(3);
int rndNumberY = rnd.Next(3);
Button random = btnArray[rndNumberX, rndNumberY];
random.PerformClick();
}
starting = false;
}
}
Can you help me fix this problem with a solution because it is hard for me to figure out what happened?
I thought it might be the code I entered in the form load.
You'll need to remove the generation of those buttons in your frmSlide_Load event handler.
You'll also need to assign your existing buttons to btnArray.
I'll demonstrate how to do that using object initializer.
Comment out all lines in frmSlide_Load
Add InitializeSliderButtons method
Add InitializeSliderButtons() line in frmSlide
Handle distanceX == 50 && distanceY == 0 related checks\logic in allNumberButton_Click. The are probably not correct values as those existing buttons look different in width\height\spacing.
public frmSlide()
{
InitializeComponent();
InitializeSliderButtons();
}
public void InitializeSliderButtons()
{
btnArray = new Button[,]
{
{
btn1,
btn2,
btn3
},
{
btn4,
btn5,
btn6
},
{
btn7,
btn8,
btnBlank
}
};
foreach (var button in btnArray)
{
button.Click += new EventHandler(this.allNumberButton_Click);
}
blkButton = btnArray[rows - 1, cols - 1];
blkButton.Text = " ";
}
private void frmSlide_Load(object sender, EventArgs e)
{
// blkButton.Text = " ";
// int curNum = 1;
// for (int x = 0; x < rows; x++)
// {
// for (int y = 0; y < cols; y++)
// {
// Button b;
// b = new Button();
// b.Location = new Point(100 + (y * 50), 100 + (x * 50));
// b.Height = 40;
// b.Width = 40;
// b.Text = curNum.ToString();
// btnArray[x, y] = b;
// b.TextAlign = ContentAlignment.MiddleCenter;
// b.Font = new Font(FontFamily.GenericSerif, (float)15.0);
// b.Click += new System.EventHandler(this.allNumberButton_Click);
// this.Controls.Add(b);
// curNum++;
// }
// }
// btnArray[rows - 1, cols - 1].Text = "";
// blkButton = btnArray[rows - 1, cols - 1];
// blkButton.Text = " ";
}
To determine your form button values, you'll look at the Location property of the Button on the designer (in the Properties window\view)
In the above screenshot, it's 170, 122 (X, Y). The button to the right of it would have to be 220, 122 (X+50, Y+0) for your current logic\check to work. You'll reflect on those locations and differences and update your logic\checks to whatever you determine it should be.
I must say you need to take break and sit back. You are making this FAR more complicated than it has to be. Remember… KISS (Keep It Super Simple).
From what you stated, you are given a form with nine (9) Button objects on the form (btn1, btn2…btn9). The buttons are displayed in a 3x3 array or 3 rows of 3 columns. Given this, it is not a bad idea as you started to make a 3x3 Button array to “hold” the buttons.
One thing that you need to “forget about” at this time is the “blank” button. To start, let’s just say it is another button, it is irrelevant at this point if it is “blank” or not. So, let us fill the 3x3 Button array using the “existing” Buttons on the form. In addition, since we want ALL the button’s Click event to fire the same event, we can go ahead and wire them up also. Something like…
public void InitializeSliderButtons() {
btnArray[0, 0] = btn1;
btnArray[0, 1] = btn2;
btnArray[0, 2] = btn3;
btnArray[1, 0] = btn4;
btnArray[1, 1] = btn5;
btnArray[1, 2] = btn6;
btnArray[2, 0] = btn7;
btnArray[2, 1] = btn8;
btnArray[2, 2] = btn9;
foreach (var button in btnArray) {
button.Click += new EventHandler(allNumberButton_Click);
}
}
Now we have the Buttons in a nice and neat 3x3 array. Next, we need to move to the buttons “Click” event allNumberButton_Click. When this event is fired, the first problem we have is figuring out “which” button was clicked. This is easily done, however, there is one button that we want to “ignore” if it is clicked and it doesn’t matter “which” button it is. That button would be the Button that has the text set to a blank string. In other words, if the blank button is clicked then we do not have to do anything. So, the first check in this event is to check for this blank button.
private void allNumberButton_Click(object sender, EventArgs e) {
Button clickedButton = (Button)sender;
if (clickedButton.Text == "")
return;
// if code execution gets here then the clicked button is NOT the blank button
}
After this if the code did not return, then we DO need to find out “which” Button was clicked. In this case the only way we can tell which button is clicked is by looking at the button name. We already know the button names are btn1, btn2… etc. However, EVEN if we know the button name, then we would still have to figure out “where” that button was in relation to the 3x3 button array. It is irrelevant what the button name is, we need the position in the button array. In other words, I only care about “which” button was clicked in relation to the 3x3 button array.
If we can get the clicked button's X,Y position in the btnArray, then it will make it trivial to check the buttons above, below, left and right of this button. If any of the above, below, left or right buttons are empty/blank, then we can switch the two button’s text value.
Given this, I will use a Point object as it has an X and Y property we can use. To help we will create a very simple method that takes a Button, and returns a Point. We will know the “position” of the button by its name. So btn1 would return Point(0,0), btn2 would return Pont(0,1)… etc. This will help in the click event by giving us the X and Y coordinates of the clicked button in relation to the 3x3 button array. If we are given a button that does not match any of the name’s we are looking for then we will return a -1, -1. This method may look something like…
private Point GetButtonPosition(Button button) {
if (button.Name == "btn1")
return new Point(0, 0);
if (button.Name == "btn2")
return new Point(0, 1);
if (button.Name == "btn3")
return new Point(0, 2);
if (button.Name == "btn4")
return new Point(1, 0);
if (button.Name == "btn5")
return new Point(1, 1);
if (button.Name == "btn6")
return new Point(1, 2);
if (button.Name == "btn7")
return new Point(2, 0);
if (button.Name == "btn8")
return new Point(2, 1);
if (button.Name == "btn9")
return new Point(2, 2);
return new Point(-1, -1);
}
This will update the click method like below…
private void allNumberButton_Click(object sender, EventArgs e) {
Button clickedButton = (Button)sender;
if (clickedButton.Text == "")
return;
Point buttonPosition = GetButtonPosition(clickedButton);
}
Now that we have the clicked buttons position in relation to the 3x3 all we need to do is check to see if one of the buttons above, below, left or right of this button is an “empty/blank” button. In this example, I have created another method that takes a Button and returns a Point object.
In this method, we will check buttons above, below, left and right of the given button and see if any of those buttons are the empty/blank button. If we find one of the buttons IS the empty/blank button, then, we will return the X, Y position in relation to the 3x3 array of that blank button. If none of the buttons above, below, left and right are the blank button, then we will return a -1, -1 to indicate that none of the button are the blank button. This method may look something like…
private Point GetBlankButtonNextToGivenButtonPosition(Point btnPosition) {
// check buttons to the left and right of the given button
if (btnPosition.X - 1 >= 0) {
if (btnArray[btnPosition.X - 1, btnPosition.Y].Text == "") {
return new Point(btnPosition.X - 1, btnPosition.Y);
}
}
if (btnPosition.X + 1 < 3) {
if (btnArray[btnPosition.X + 1, btnPosition.Y].Text == "") {
return new Point(btnPosition.X + 1, btnPosition.Y);
}
}
// Check for buttons above and below the given button
if (btnPosition.Y - 1 >= 0) {
if (btnArray[btnPosition.X, btnPosition.Y - 1].Text == "") {
return new Point(btnPosition.X, btnPosition.Y - 1);
}
}
if (btnPosition.Y + 1 < 3) {
if (btnArray[btnPosition.X, btnPosition.Y + 1].Text == "") {
return new Point(btnPosition.X, btnPosition.Y + 1);
}
}
// blank not found
return new Point(-1, -1);
}
With this, now we can check and see if any of the buttons above, below, right or left of the clicked button is the blank button. When we call the method above, IF we get a Point with values of -1, -1, then we know that we do NOT need to swap the button text values. On the other hand, if we get any other number then that would indicate that there IS a blank button next to the clicked button. With this we would have all the info we need to swap the text values. We have the position of the clicked button, and we also have the position of the blank button “next” to the clicked button. This should complete the Click event code…
private void allNumberButton_Click(object sender, EventArgs e) {
Button clickedButton = (Button)sender;
if (clickedButton.Text == "")
return;
Point buttonPosition = GetButtonPosition(clickedButton);
if (buttonPosition.X != -1) {
Point blankPosition = GetBlankButtonNextToGivenButtonPosition(buttonPosition);
if (blankPosition.X != -1) {
btnArray[blankPosition.X, blankPosition.Y].Text = clickedButton.Text;
clickedButton.Text = "";
}
}
if (BoardIsCorrect()) {
MessageBox.Show("You solved the puzzle!");
}
}
I have another method called BoardIsCorrect to check and see if the numbers are in the correct sequence and if so, return true. This and the start and reset methods are also added below.
public Button[,] btnArray = new Button[3, 3];
Random rand = new Random();
private void frmSlide_Load(object sender, EventArgs e) {
InitializeSliderButtons();
}
private bool BoardIsCorrect() {
if (btnArray[0, 0].Text == "1" &&
btnArray[0, 1].Text == "2" &&
btnArray[0, 2].Text == "3" &&
btnArray[1, 0].Text == "4" &&
btnArray[1, 1].Text == "5" &&
btnArray[1, 2].Text == "6" &&
btnArray[2, 0].Text == "7" &&
btnArray[2, 1].Text == "8"
) {
return true;
}
return false;
}
private void btnStart_Click(object sender, EventArgs e) {
List<int> numbers = new List<int> { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
int nextRand;
int randIndex;
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
randIndex = rand.Next(0, numbers.Count);
nextRand = numbers[randIndex];
if (nextRand != 9) {
btnArray[i, j].Text = nextRand.ToString();
}
else {
btnArray[i, j].Text = "";
}
numbers.RemoveAt(randIndex);
}
}
}
private void btnReset_Click(object sender, EventArgs e) {
int rows = 3;
int cols = 3;
int count = 1;
for (int r = 0; r < rows; r++) {
for (int c = 0; c < cols; c++) {
btnArray[r, c].Text = count++.ToString();
}
}
btnArray[2, 2].Text = "";
}
I hope this make sense.
so I created my own private void that can create buttons
private void addButtonsToForm()
{
for (int i = 0; i < 26; i++)
{
Button currentNewButton = new Button();
currentNewButton.Size = new Size(20, 30);
currentNewButton.Location = new Point(20 + 25 * i, 420);
currentNewButton.Text = ((char)(65 + i)).ToString();
currentNewButton.Click += LetterClicked;
letters[i] = currentNewButton;
this.Controls.Add(letters[i]);
}
}
The buttons are alphabets and will be accessed when the user wants to choose a letter ... but the problem is I'm trying to figure out how to go back when the user clicked or selected a button..
Originally I wanted to do was i could just hide all the buttons created and just make the previous button visible but for some reason it only hides the only button that is clicked
//this is under private void LetterClicked(object sender, EventArgs e)
Button selectedLetter = (Button)sender;
selectedLetter.Enabled = false;
i thought of stupid codes like
addbuttonstoform().visible = false; but of course that won't work.. but you might get an idea to where i want to go.... it's a bit confusing to explain... I'm new in c# and i'm creating a guess the word game so help could be great..
Here is a working solution for your problem. See below:
using System;
using System.Drawing;
using System.Windows.Forms;
namespace Alphabets
{
public partial class Form1 : Form
{
private Button[] _letters;
public Form1()
{
InitializeComponent();
AddButtonsToForm();
}
private void AddButtonsToForm()
{
_letters = new Button[26];
for (int i = 0; i < 26; i++)
{
Button currentNewButton = new Button
{
Name = "BtnLetter"+ ((char)(65 + i)),
Size = new Size(20, 30),
Location = new Point(20 + 25 * i, 420),
Text = ((char) (65 + i)).ToString()
};
currentNewButton.Click += LetterClicked;
_letters[i] = currentNewButton;
this.Controls.Add(_letters[i]);
}
}
private void LetterClicked(object sender, EventArgs e)
{
var selectedLetter = (Button) sender;
//hide all other buttons
foreach (var letter in _letters)
{
if (letter.Text != selectedLetter.Text)
{
var buttons = this.Controls.Find("BtnLetter" + letter.Text, true);
buttons[0].Enabled = false;
}
}
}
}
}
When btnAsset is double-clicked, it should go to allButton_Click.
But it only goes in one click. how can I do that?
public void Add(MainForm frm)
{
this.form1 = frm;
for (int i = 0; i < 10; i++)
{
btnAsset[i] = new Button();
btnAsset[i].Tag = i;
btnAsset[i].Name = "Asset-" + i.ToString();
btnAsset[i].Width = 150;
btnAsset[i].Height = 120;
btnAsset[i].Visible = true;
btnAsset[i].BackColor = Color.GreenYellow;
form1.flowLayoutVideo.Controls.Add(btnAsset[i]);
btnAsset[i].DoubleClick += new EventHandler(allButton_Click);
}
}
should go here when double clicked
void allButton_Click(object sender, EventArgs e)
{
Button p = sender as Button;
if (p != null)
{
int i = (int)p.Tag;
MessageBox.Show((i + 1).ToString() + ". seçildi");
}
}
Look what the docs says about it:
By default, the ControlStyles.StandardClick and ControlStyles.StandardDoubleClick style bits are set to false for the Button control, and the DoubleClick event is not raised.
You can change this behaviour by creating your own button class deriving from Button and change the style bits.
This function dynamically creates nine buttons for use in a game I am making. You can see what attributes I give to the button.
private void createbuttons()
{
int tot = 0;
int x = 100;
int y = 100;
while(tot < 9)
{
string buttonsname = (tot + "button").ToString();
Button creating = new Button();
creating.Name = buttonsname;
creating.Size = new Size(100, 100);
creating.Click += delegate
{
MessageBox.Show("You clicked me!");
};
creating.Text = buttonsname;
if(x > 300)
{
y += 100;
x = 100;
}
creating.Location = new Point(x, y);
Controls.Add(creating);
tot += 1;
x += 100;
}
}
What I want to know is how to reference these buttons in different parts of the same form. Specifically when 'Start Game' is clicked I want to change the text for each button to something different.
private void button10_Click(object sender, EventArgs e)
{
//What would I write here to change the text?
}
You can access the buttons by enumerating the controls, or you could create a list of buttons for future reference, and use that list later.
Here is how you do it with a list:
private IList<Button> addedButtons = new List<Button>();
private void createbuttons() {
int tot = 0;
int x = 100;
int y = 100;
while(tot < 9) {
string buttonsname = (tot + "button").ToString();
Button creating = new Button();
creating.Name = buttonsname;
creating.Size = new Size(100, 100);
creating.Click += delegate {
MessageBox.Show("You clicked me!");
};
creating.Text = buttonsname;
if(x > 300) {
y += 100;
x = 100;
}
creating.Location = new Point(x, y);
addedButtons.Add(creating); // Save the button for future reference
Controls.Add(creating);
tot += 1;
x += 100;
}
}
Now you can do this:
foreach (var btn : addedButtons) {
btn.Text = "Changed "+btn.Text;
}
The form has a property Controls that holds all child controls. To find a child control by its Name property use method Find, which returns the array, because there may be several control with the same Name, but if you make sure that names exist, are unique, and you know their type (Button) you can just take the first item from the array and cast it:
private void button10_Click(object sender, EventArgs e)
{
Button buttonNamedFred = (Button)this.Controls.Find("Fred", false)[0];
buttonNamedFred.Text = "I'm Fred";
}
I have an array of buttons, like this:
int x = 0, y = 0;
butt2 = new Button[100];
for (int i = 0; i < 100; i++)
{
butt2[i] = new Button();
int names = i;
butt2[i].Name = "b2" + names.ToString();
butt2[i].Location = new Point(525 + (x * 31), 70 + (y * 21));
butt2[i].Visible = true;
butt2[i].Size = new Size(30, 20);
butt2[i].Click += new EventHandler(butt2_2_Click); //problem lies here (1)
this.Controls.Add(butt2[i]);
}
private void butt2_2_Click(object sender, EventArgs e)
{
// want code here
}
I want to change the back color of the button when clicked. I was thinking of passing i to be able to do this:
butt2[i].BackColor = Color.Green;
This should do the trick:
private void butt2_2_Click(object sender, EventArgs e)
{
Button pushedBtn = sender as Button;
if(pushedBtn != null)
{
pushedBtn.BackColor = Color.Green;
}
}
And this holds for most UI events, the 'object sender' parameter refers to the control that 'sent'/'fired' the event.
To learn more about C# event handling, I would start here.
Also, here is a SO question about GUI event handling, answered nicely by Juliet (accepted answer).
Hope this helps.