In a hangman game I am trying to write using C#.Net I am trying to get a button to call a function but it can not use any variables I have defined earlier in the code.
Is there anyway that code added into the button can see variables that are stored outside of it?
I am new to this programming so please explain if I am missing something really obvious. Sorry!
Thanks for any help guys.
Dan
Loading
DanPosted Nov 18, 2007, 5:48 PM
With your help I now have it so that the button works and that it is correctly identifying if the input matches any of the letters.
Next I need to make it so that instead of just printing out which position it matched, it actually does something. I will work on this and come back if I have any more problems :-)
Thanks again :-D
AlanPosted Nov 18, 2007, 7:35 AM
Although it's not particularly important, one thing you could do differently is to use the string indexer to get each character out of the 'answer' string rather than converting it to a char array first. You could then replace splitAnswer[i] with answer[i].
Unless you've set the maximum length of txtEntry to one, I'd also replace this line:
char input = char.Parse(txtEntry.Text);
with this one so that an exception is not thrown if the user enters more than one character into the textbox:
char input = (txtEntry.Text)[0];
Another minor point is that it's not necessary to use '== true' when testing a bool variable in an 'if' statement, because the variable itself either represents a 'true' or 'false' value. Similarly, you can simplify the checkInput() method to just one line:
return (userInput == letterCheck);
You've actually hived off a bit more code than I anticipated. This is more what I had in mind:
namespace WindowsApplication1
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
public void Form1_Load(object sender, EventArgs e)
{
string answerFile = "words.txt"; //Select Answer File
TextReader tr = new StreamReader(answerFile); //Create Reader
string wordsImported = tr.ReadToEnd(); //Import words from answer file
string[] wordsSplit = wordsImported.Split(','); //Split words into array
int wordCount = wordsSplit.GetLength(0); //Get number of words available
//wordCount = convertWordCount(wordCount);
int selectWord = randomNumber(wordCount); //Generate Random number to select the answer
string answer = wordsSplit[selectWord]; // Store answer into variable 'answer'
int ansLength = answer.Length;
int maxTries = ansLength + 5;
for (int i = 0; i <= ansLength; i++)
{
lblAnswer.Text = lblAnswer.Text + "_ ";
}
char input = (txtEntry.Text)[0];
checkAnswer(answer, input);
}
private int randomNumber(int wordsAmount)
{
Random randNum = new Random(); //Create Random number generator
int wordSelect = randNum.Next(wordsAmount); // Generate random number and store value
return wordSelect; //Return random number
}
private bool checkInput(char userInput,char letterCheck)
{
return (userInput == letterCheck);
}
private void checkAnswer(string answer, char input)
{
for (int i = 0; i < answer.Length; i++)//generate which letter to check
{
char checkLetter = answer[i]; //store the letter to check input against
bool checkInputResult = checkInput(input, checkLetter); // call function to check input
if (checkInputResult) // If the input matches the stored letter
{
lblAnswer.Text = lblAnswer.Text + " correct"; //Add correct to Text box
}
else
{
lblAnswer.Text = lblAnswer.Text + " wrong"; //Add wrong to text box
}
}
}
}
When you declare a field as private (which is the default), then it can only be accessed from within the form itself. I'm therefore puzzled by what you say in your last post unless you've got the button on a different form?
DanPosted Nov 17, 2007, 4:40 PM
I tried moving:
string answer;
int ansLength;
To right after the class declaration, but to let my button access them I had to put public in front of them. If i put private in front like in Scott's example it just gives a warning that they are declared but never used, even though I mention them later in the code.
DanPosted Nov 17, 2007, 1:16 PM
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.IO;
namespace WindowsApplication1
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
public void Form1_Load(object sender, EventArgs e)
{
string answerFile = "words.txt"; //Select Answer File
TextReader tr = new StreamReader(answerFile); //Create Reader
string wordsImported = tr.ReadToEnd(); //Import words from answer file
string[] wordsSplit = wordsImported.Split(','); //Split words into array
int wordCount = wordsSplit.GetLength(0); //Get number of words available
//wordCount = convertWordCount(wordCount);
int selectWord = randomNumber(wordCount); //Generate Random number to select the answer
string answer = wordsSplit[selectWord]; // Store answer into variable 'answer'
int ansLength = answer.Length; //Store length of the answer word
int maxTries = ansLength + 5; //Set max tries to AnsLength + 5
checkLetter(answer, ansLength);
}
private int randomNumber(int wordsAmount)
{
Random randNum = new Random(); //Create Random number generator
int wordSelect = randNum.Next(wordsAmount); // Generate random number and store value
return wordSelect; //Return random number
}
private bool checkInput(char userInput,char letterCheck)
{
if (userInput == letterCheck)
{
return true;
}
else
{
return false;
}
}
private void checkLetter(string answer, int ansLength)
{
char[] splitAnswer = answer.ToCharArray();
for (int i = 0; i <= ansLength; i++)
{
lblAnswer.Text = lblAnswer.Text + "_ ";
}
char input = char.Parse(txtEntry.Text);
for (int i = 0; i < ansLength; i++)//generate which letter to check
{
char checkLetter = splitAnswer[i]; //store the letter to check input against
bool checkInputResult = checkInput(input, checkLetter); // call function to check input
if (checkInputResult == true) // If the input matches the stored letter
{
lblAnswer.Text = lblAnswer.Text + " correct"; //Add correct to Text box
}
else
{
lblAnswer.Text = lblAnswer.Text + " wrong"; //Add wrong to text box
}
}
}
}
}
DanPosted Nov 17, 2007, 1:16 PM
I have just called the new function (which i made by hiving off the code) in the form_load area, but even if I try to call this from a button it is not going to work.
Is there anyway I can just "listen" for an input into the txtArea.text?? That way I could put this code to "listen" into the form_load and then every time a letter is entered into the box call the function???
I will put some code in so that once the function has been called (when somebody enters a value) it clears the value in the text box, ready for the next input.
What do you think?
DanPosted Nov 17, 2007, 12:31 PM
Are there any glaring weaknesses in the code I have posted, i.e things I am just not doing right, or any way I have made more work than I need to? I would like to try and get rid of any poor practice as I go along.
The longer I write poor code the harder it will become to change later.
AlanPosted Nov 16, 2007, 2:47 PM
As Scott surmised, it's a scoping problem.
'input' and 'checkLetter' are local variables declared in the Form1_Load method and are not therefore visible from the button's click eventhandler.
In place of 'input', you could use txtEntry[0] i.e. the first and only character in the TextBox. However, the derivation of 'checkLetter' is more complex and it might be an idea to hive off the code which gets this, or the whole 'splitAnswer' array, into a separate method which can then be called from any other method in the class.
DanPosted Nov 16, 2007, 2:11 PM
I currently have it set to 'g' just to test. What I want to do is have a button that when clicked checks what is entered into the txtEntry box.
At the moment it just checks it when the program runs, so there is no way for the user to input something, it will always check 'g' at the moment as that is what is in the txt box and it automatically runs the function when the program loads.
When I tried to use a button to call the function, it would not let me pass 'input' and 'checkLetter' into the function. It says they do not exist in this context.
DanPosted Nov 16, 2007, 2:08 PM
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.IO;
namespace WindowsApplication1
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
public void Form1_Load(object sender, EventArgs e)
{
string answerFile = "words.txt"; //Select Answer File
TextReader tr = new StreamReader(answerFile); //Create Reader
string wordsImported = tr.ReadToEnd(); //Import words from answer file
string[] wordsSplit = wordsImported.Split(','); //Split words into array
int wordCount = wordsSplit.GetLength(0); //Get number of words available
//wordCount = convertWordCount(wordCount);
int selectWord = randomNumber(wordCount); //Generate Random number to select the answer
string answer = wordsSplit[selectWord]; // Store answer into variable 'answer'
int ansLength = answer.Length;
int maxTries = ansLength + 5;
char[] splitAnswer = answer.ToCharArray();
for (int i = 0; i <= ansLength; i++)
{
lblAnswer.Text = lblAnswer.Text + "_ ";
}
char input = char.Parse(txtEntry.Text);
for (int i = 0; i < ansLength; i++)//generate which letter to check
{
char checkLetter = splitAnswer[i]; //store the letter to check input against
bool checkInputResult = checkInput(input, checkLetter); // call function to check input
if (checkInputResult == true) // If the input matches the stored letter
{
lblAnswer.Text = lblAnswer.Text + " correct"; //Add correct to Text box
}
else
{
lblAnswer.Text = lblAnswer.Text + " wrong"; //Add wrong to text box
}
}
}
private int randomNumber(int wordsAmount)
{
Random randNum = new Random(); //Create Random number generator
int wordSelect = randNum.Next(wordsAmount); // Generate random number and store value
return wordSelect; //Return random number
}
private bool checkInput(char userInput,char letterCheck)
{
if (userInput == letterCheck)
{
return true;
}
else
{
return false;
}
}
}
}
Scott LyslePosted Nov 16, 2007, 2:03 PM
It sounds like you have a scope issue; you did not show any of your code but I would guess that you are talking about accessing variables that you intended to have class wide scope. If that is the case then you'd need to declare your variables after the class declaration. Here is a short example; in it a string variable is declared within the class, it is then accessed in the constructor and then again in the button click event handler:
public partial class frmCreateStudy : Form { private string mDate; public frmCreateStudy() { InitializeComponent(); mDate = DateTime.Now.ToShortDateString(); } private void btnReport_Click(object sender, EventArgs e) { MessageBox.Show(mDate); } }