How to choose the Nth picturebox - c#

I am trying to make a memory game. I have 16 different pictureboxes(pbx1, pbx2...).
And now I am trying to make them revert to questionmarks after a wrong guess. This is what I've so far done:
void questionMarker(int lastBoxCLicked)
{
if(lastBoxClicked == 1)
{
pbx1.Image = Image.FromFile("../Bilder/Frågetecken.png");
}
else if(lastBoxClicked == 2)
{
pbx2.Image = Image.FromFile("../Bilder/Frågetecken.png");
}
else if (lastBoxClicked == 3)
{
pbx3.Image = Image.FromFile("../Bilder/Frågetecken.png");
}
else if (lastBoxClicked == 5)
{
pbx4.Image = Image.FromFile("../Bilder/Frågetecken.png");
}
}
But this becomes quite tedious and horrendous to look at as I have 16 pbx'es. Is there any way to write it like this?:
void questionMarker(int lastBoxClicked)
{
pbx[lastBoxClicked].Image = Image.FromFile("../Bilder/Frågetecken.png");
}
If I put this code in it just says that there is nothing named pbx.

Try this:
PictureBox[] PictureBoxArray = new PictureBox[3];
This creates an array of 3 picture boxes called PictureBoxArray.
You can loop through like an ordinary array or access certain picture boxes using PictureBoxArray[i]

Just use the "recurse" option of Controls.Find(). This will find the control "by name" no matter where or how deeply nested it is on the form:
Image questionMark = Image.FromFile("../Bilder/Frågetecken.png");
void questionMarker(int lastBoxCLicked)
{
PictureBox pb = this.Controls.Find("pbx" + lastBoxCLicked, true).FirstOrDefault() as PictureBox;
if (pb != null)
{
pb.Image = questionMark;
}
}

Related

Iterating over a bool list/array returns all false

I'm creating this windows forms c# app where i can load images from folder, choose few of them by clicking on their image and then copy them to another folder. So far everything seemed good but now i stumbled upon problem. I have 10 bools which are representing each image status ( selected or not selected).
public partial class Form1 : Form
{
public bool selected1 = false;
public bool selected2 = false;
public bool selected3 = false;
public bool selected4 = false;
public bool selected5 = false;
public bool selected6 = false;
public bool selected7 = false;
public bool selected8 = false;
public bool selected9 = false;
public bool selected10 = false;
these are those bools.
Next i put them in the list ( i tested array too )
private List<bool> selectedBools = new List<bool>();
And then i assign bools to the list in the Public Form1():
selectedBools = new List<bool> { selected1, selected2, selected3, selected4, selected5, selected6, selected7, selected8, selected9, selected10 };
Each image status is controlled by this piece of code ( every picturebox_click has the same code with changed numbers )
private void pictureBox2_Click_1(object sender, EventArgs e)
{
if (selected1 == false)
{
pctBox1.Image = null;
selected1 = true;
pctBox1.BackColor = Color.Red;
}
else if (selected1 == true)
{
selected1 = false;
pctBox1.BackColor = Color.White;
try
{
pctBox1.Image = Image.FromFile(filePaths[0 + Page * 10]); // refresh image
}
catch
{
}
}
}
Then when i press to change "Page" ( which just moves every image by 10 ) i set all of the bools again to false.
The problem is when i want to "upload" those images to the folder ( just copy selected there):
private void UploadAllButton_Click(object sender, EventArgs e)
{
Console.WriteLine(selected1.ToString() + selected2 + selected3 + selected4 + selected5 + selected6 + selected7 + selected8 + selected9 + selected10);
DialogResult result = MessageBox.Show(this, "Are you sure?", "Upload all", MessageBoxButtons.YesNo, MessageBoxIcon.Question);
if (result == DialogResult.Yes)
{
List<int> selectedBooleansIndexes = new List<int>();
int i = 10;
foreach (bool selected in selectedBools)
{
i--;
Console.WriteLine(selected);
Console.WriteLine(selectedBools[i]);
if (selected == true)
{
int index = selectedBools.FindIndex(a => a = true);
selectedBooleansIndexes.Add(index);
Console.WriteLine(selectedBooleansIndexes.Count);
}
if (i == 0)
{
Console.WriteLine(selected1.ToString() + selected2 + selected3 + selected4 + selected5 + selected6 + selected7 + selected8 + selected9 + selected10);
MessageBox.Show(this, selectedBooleansIndexes.Count.ToString(), "siur");
}
When I select some images, their select bool changes to true. So i wanted to grab those that are set to true and get their indexes so later i can you those indexes when copying files. Problem is when i run if (selected == true ) all of them seem to be false and nothing happens. I checked that by manually typing out in console status of every bool and when i do that, it works as intended. So my problem is, when i use foreach loop, every bool status is false even though it isn't ( i checked it many times because i thought that something overrides them in diffrent place in code). Maybe i'm missing something but it's strange.
Let's simplify your code in order to explain:
bool b1 = false;
bool b2 = false
Up to here, everything is as expected by you. b1 and b2 are both false.
List<bool> l = new List<bool>(){b1, b2};
You now have a list with copies of b1 and b2. That is because booleans are value types.
What does that mean? If you change b1, [0] will not change with it. If you change l[0], b1 will not change with it. Same for b2 and l[1]. They are totally independent.
Let's move to the larger problem now. You definitely don't want copies, so don't create them.
Instead of
public bool selected1 = false;
[...]
public bool selected10 = false;
use the list only and access the entries via their index. Think of an application which has 1000 images instead of 10. You would not want to declare 1000 variables, would you?
Let's create a list of 10 booleans, initialized with false (because that's their default value):
List<bool> selected = new List<bool>(new bool[10]);
Let's also put all your picture boxes into a list:
List<PictureBox> pictures = List<PictureBox>{pctBox1, ... pctBox10};
Whenever pctBox1 changes, pictures[0] will change with it. It is not a copy. This will work, because PictureBox is a reference type instead of a value type.
That way, you can define a single method which does all the things:
private void DoSomething(int index)
{
if (selected[index] == false)
{
pictures[index].Image = null;
selected[index] = true;
pictures[index].BackColor = Color.Red;
}
else // DONE: if (selected[index] == true) is unnecessary, because true is the only option left
{
selected[index] = false;
pictures[index].BackColor = Color.White;
try
{
pictures[index].Image = Image.FromFile(filePaths[index + Page * 10]); // refresh image
}
catch { } // TODO: fix bad error handling
}
}
and every click event handler becomes as simple as
private void pictureBox2_Click_1(object sender, EventArgs e)
{
DoSomething(0); // change index only
}
We would typically further simplify the DoSomething() method.
private void DoSomething(int index)
{
selected[index] = !selected[index]; // Flip the value
pictures[index].BackColor = selected[index]?Color.White:Color.Red; // Choose the back color
pictures[index].Image = null; // Reset always, since it doesn't really matter
if (selected[index])
{
try
{
pictures[index].Image = Image.FromFile(filePaths[index + Page * 10]); // refresh image
}
catch {} // TODO: still fix bad error handling
}
}
I think that's enough for today. One would probably not create 10 picture boxes manually either, but have them be created in a loop.

Public void int increment by 1 every loop (Beginner)

I'd basically like to know how I can increase Player.SetPoints(); by 1 every time it loops. I got this in my class public void SetPoints(int p) { points = p; }, just thought that would be worth mentioning. So far the only way I've gotten this to work is to use Player.SetPoints(+1); but that only puts 1 to the scoreboard and never increases again. Sorry If I'm not clear enough, I'm very new to programming. This is a sample of my code so you might be able to understand it a bit more, I'm making a tic tac toe game as an assignment for school.
if (Btn1.Text != "" && Btn2.Text != "" && Btn3.Text != "")
{
if (Btn1.Text == Btn2.Text && Btn1.Text == Btn3.Text)
{
Btn1.BackColor = Color.Green;
Btn1.ForeColor = Color.White;
Btn2.BackColor = Color.Green;
Btn2.ForeColor = Color.White;
Btn3.BackColor = Color.Green;
Btn3.ForeColor = Color.White;
if (Btn1.Text == "X")
{
MessageBox.Show(lblpl1.Text + " Has Won!");
Player1.SetPoints(+0);
playerscore1.Text = Player1.GetPoints().ToString();
}
else
{
MessageBox.Show(lblpl2.Text + " Has Won!");
Player2.SetPoints(+0);
playerscore2.Text = Player2.GetPoints().ToString();
}
click1++;
click2++;
click3++;
click4++;
click5++;
click6++;
click7++;
click8++;
click9++;
restartbtn.Visible = true;
}
}
In order increase something in each button click you need to save the previous value in a variable. You are doing a similar think with clicks:
click1++;
Your method sets the points to a given value. If you give it 1 it sets it to 1. It looks like you don't want to set points to an individual value, you want to increase it each time, so instead of declaring a method like that you can change it to:
public void IncreasePoints()
{
points++;
}
And simply call it without passing any value.
Player1.IncreasePoints();

Interchange positions of two buttons

I want to replace button location (Interchange location )by black button when i click it and it is next to black button (b9=black button and lable1 is a temp for saving location).
I made this method :
void checkLocation()
{
if (ActiveControl.Location == new Point(5, 7))//-----------for button 1
{
if (b9.Location == new Point(83, 7) || b9.Location == new Point(5, 71))
{
label1.Location = ActiveControl.Location;
ActiveControl.Location = b9.Location;
b9.Location = label1.Location;
}
}// it continue for every button
and I write this code for every button_click
private void button1_Click(object sender, EventArgs e)
{
checkLocation();
}
now,some button don't work currently . what is wrong ?
by thanks from p.s.w.g
I think it is shorter and fit :
void swapLocation()
{
var tmp = ActiveControl.Location;
if((ActiveControl.Location.X==b9.Location.X)&&(Math.Abs(b9.Location.Y-ActiveControl.Location.Y)<=60))
{
ActiveControl.Location = b9.Location;
b9.Location = tmp;
}
if ((ActiveControl.Location.Y == b9.Location.Y) && (Math.Abs(b9.Location.X-ActiveControl.Location.X) <= 70))
{
ActiveControl.Location = b9.Location;
b9.Location = tmp;
}
}
Just do this to swap the locations of two controls:
void swapLocation()
{
var tmp = ActiveControl.Location;
ActiveControl.Location = b9.Location;
b9.Location = tmp;
}
Or more generally
void swapLocation(Control x, Control y)
{
var tmp = x.Location;
x.Location = y.Location;
y.Location = tmp;
}
...
swapLocation(ActiveControl, b9);
Update
It looks like you're trying to implement a version of the 15-puzzle. There are numerous ways to solve this, but to avoid a radical rewrite of your program I'd recommend this:
private int buttonWidth = 82;
private int buttonHeight = 82; // adjust these values as needed
private void button_Click(object sender, EventArgs e)
{
if ((Math.Abs(ActiveControl.Location.X - b9.Location.X) == 0 &&
Math.Abs(ActiveControl.Location.Y - b9.Location.Y) == buttonHeight) ||
(Math.Abs(ActiveControl.Location.X - b9.Location.X) == buttonWidth &&
Math.Abs(ActiveControl.Location.Y - b9.Location.Y) == 0))
{
swapLocation(ActiveControl, b9);
}
}
This basically checks to see if the ActiveControl is either directly above, below, to the left, or the right of b9, and if it is, swaps them. You can use this click handler for all buttons 1 through 8. Note this method only works with the buttons are a fixed width and height.

Can´t check if array values are true from another class in main class

I am programming a basic writing game in C#. The game will randomly show picture in a picturebox. The pictures is stored in an array in a different class than the main class.
The code to the class looks like this :
public class bildelisteDyr
{
public static Bitmap bildeListe (int index)
{
Bitmap[] bildeListe = new Bitmap[21];
bildeListe[0] = Properties.Resources.ål;
bildeListe[1] = Properties.Resources.ant;
bildeListe[2] = Properties.Resources.bird;
bildeListe[3] = Properties.Resources.bear;
bildeListe[4] = Properties.Resources.butterfly;
bildeListe[5] = Properties.Resources.cat;
bildeListe[6] = Properties.Resources.chicken;
bildeListe[7] = Properties.Resources.dog;
bildeListe[8] = Properties.Resources.elephant;
bildeListe[9] = Properties.Resources.fish;
bildeListe[10] = Properties.Resources.goat;
bildeListe[11] = Properties.Resources.horse;
bildeListe[12] = Properties.Resources.ladybug;
bildeListe[13] = Properties.Resources.lion;
bildeListe[14] = Properties.Resources.moose;
bildeListe[15] = Properties.Resources.polarbear;
bildeListe[16] = Properties.Resources.reke;
bildeListe[17] = Properties.Resources.sheep;
bildeListe[18] = Properties.Resources.snake;
bildeListe[19] = Properties.Resources.spider;
bildeListe[20] = Properties.Resources.turtle;
return bildeListe[index];
}
}
When calling on the values in the array to show picture randomly in the picturebox it all works well. This is done like this :
pictureBox1.Image = bildelisteDyr.bildeListe(r.Next(0, 20));
But I have three times where I need the code to check the value of the picturebox to do a something. I have one play sound button, one button that give a label a text and one button to check given answer from a textbox. None of them seems to work. Here are some code :
Give text to label :
if (pictureBox1.Image == bildelisteDyr.bildeListe(0))
{
svarPåOppgave.Text = "ÅL";
}
else if (pictureBox1.Image == bildelisteDyr.bildeListe(1))
{
svarPåOppgave.Text = "MAUR";
}
// etc.
Play sound button :
if (pictureBox1.Image == bildelisteDyr.bildeListe(0))
{
SoundPlayer player = new SoundPlayer();
player = new SoundPlayer("lyd/dyr/ål.wav");
player.PlaySync();
}
else if (pictureBox1.Image == bildelisteDyr.bildeListe(1))
{
SoundPlayer player = new SoundPlayer();
player = new SoundPlayer("lyd/dyr/enmaur.wav");
player.PlaySync();
}
// etc.
Checking if correct answer is given :
if (pictureBox1.Image == bildelisteDyr.bildeListe(0))
{
if (textBox1.Text.Trim().ToLower() == "ål")
{
riktigLyd.Play();
poengInt += 1;
textBox1.Text = "";
pictureBox1.Image = bildelisteDyr.bildeListe(tilfeldigBildet);
tekstTilLabel();
svarPåOppgave.Visible = false;
}
else
{
feilLyd.Play();
poengInt -= 1;
textBox1.Text = "";
}
String poengString = poengInt.ToString();
label1.Text = poengString;
textBox1.Select();
}
else if (pictureBox1.Image == bildelisteDyr.bildeListe(1))
{
if (textBox1.Text.Trim().ToLower() == "maur")
{
riktigLyd.Play();
poengInt += 1;
textBox1.Text = "";
pictureBox1.Image = bildelisteDyr.bildeListe(tilfeldigBildet);
tekstTilLabel();
svarPåOppgave.Visible = false;
}
else
{
feilLyd.Play();
poengInt -= 1;
textBox1.Text = "";
}
String poengString = poengInt.ToString();
label1.Text = poengString;
} // etc.
I would guess there was something wrong with the if statements like
if (textBox1.Text.Trim().ToLower() == "ål")
But I can´t seem to understand what?
To sum it up, when I debug the program I get the random picture from the other class. But when I press the buttons on the program nothing happens. No sound, no text to label and no checking of answer.
There's some unusual architectural choices here, but the specific problem you're facing is that you're re-creating the Bitmaps every time, and comparisons are performed by reference, not by value.
Change your bildelisteDyr class as follows:
public class bildelisteDyr
{
static Bitmap[] bildeListeInternal;
static bildelisteDyr() {
bildeListeInternal = new Bitmap[21];
bildeListeInternal[0] = Properties.Resources.ål;
//...
bildeListeInternal[20] = Properties.Resources.turtle;
}
public static Bitmap bildeListe (int index) {
return bildeListeInternal[index];
}
}
Some more resources on the conceptual problem:
== Operator
Value vs Reference Types

Combining ClearAll with Watermark on textbox in WPF

After trying numerous methods to get watermarking to work for me, I finally found the one modified by #Beej on this page:
Watermark / hint text / placeholder TextBox in WPF
I got it placed in my project, and it works fine, with one exception. I have multiple textboxes on each tab of a tabcontrol. At the bottom is a clear button that works to clear all the textboxes on the tab. The clear button works fine, the watermark works fine, but I can't get them to work together. The window loads with the watermarks in place, and pressing the clear button clears all the boxes, but the watermarks don't reappear until after I move through the textboxes (each one gaining and losing focus.) I have tried numerous ways to solve this, such as placing a method call to the ShowWatermark function in the button MouseUp event, but nothing has worked...Help?!
This is the Clear button method I'm using:
public void ClearTextBoxes()
{
ChildControls ccChildren = new ChildControls();
foreach (object o in ccChildren.GetChildren(rvraDockPanel, 2))
{
if (o.GetType() == typeof(TextBox))
{
TextBox txt = (TextBox)o;
txt.Text = "";
}
if (o.GetType() == typeof(DigitBox))
{
DigitBox digit = (DigitBox)o;
digit.Text = "";
}
if (o.GetType() == typeof(PhoneBox))
{
PhoneBox phone = (PhoneBox)o;
phone.Text = "";
}
if (o.GetType() == typeof(DateBox))
{
DateBox date = (DateBox)o;
date.Text = "";
}
if (o.GetType() == typeof(TextBoxWatermarked))
{
TextBoxWatermarked water = (TextBoxWatermarked)o;
water.Text = "";
}
}
}
class ChildControls
{
private List<object> listChildren;
public List<object> GetChildren(Visual p_vParent, int p_nLevel)
{
if (p_vParent == null)
{
throw new ArgumentNullException("Element {0} is null!", p_vParent.ToString());
}
this.listChildren = new List<object>();
this.GetChildControls(p_vParent, p_nLevel);
return this.listChildren;
}
private void GetChildControls(Visual p_vParent, int p_nLevel)
{
int nChildCount = VisualTreeHelper.GetChildrenCount(p_vParent);
for (int i = 0; i <= nChildCount - 1; i++)
{
Visual v = (Visual)VisualTreeHelper.GetChild(p_vParent, i);
listChildren.Add((object)v);
if (VisualTreeHelper.GetChildrenCount(v) > 0)
{
GetChildControls(v, p_nLevel + 1);
}
}
}
}
Both the ChildControls class and the TextboxWatermarked class (from the above link) are in seperate class files.
The problem is not with your code, it's with the chosen watermarked text box. It only updates the watermark when it gains or loses focus, which is an obvious flaw. You'll need to find a better implementation. Have you tried the one in extended WPF toolkit?

Categories