I have a program that quizzes the user by naming a Country (from a list) and asks the user to input it's Capital. If they get it correct, a counter for correct answers is shown with +1 added to it. If it is wrong, the same thing goes but for the incorrect counter. I finished the code for it, but whenever I use the Check Answer button, it doesn't verify the input from the TextBox anymore, and none of the counters (correct or incorrect) change at all. If the first one is right and the second is wrong, it counts both 1 for correct and 1 for incorrect. After that the code under the Check Answer button doesn't execute anymore. If I got 2 right or 2 wrong it only counts the first 1 and stops working after.
{
// Declare structure
struct Country
{
// Declare strings
public string countryName;
public string capital;
}
public partial class Form1 : Form
{
// Create List for CourseInfo
private List<Country> countryList = new List<Country>();
Country currentCountry;
public Form1()
{
InitializeComponent();
}
private void ReadFile()
{
try
{
// Call StreamReader to use imported file
StreamReader inputFile;
string line;
Country entry = new Country();
// Delimiter to separate values in text file
char[] delim = { ',' };
// Open text file
inputFile = File.OpenText("countries.txt");
while (!inputFile.EndOfStream)
{
line = inputFile.ReadLine();
// Tokenize the strings separated by the delimiter ','
string[] tokens = line.Split(delim);
entry.countryName = tokens[0]; // Tokenized entry for COUNTRY
entry.capital = tokens[1]; // Tokenized entry for CAPITAL
countryList.Add(entry);
}
}
catch (Exception ex)
{
// Shows error message
MessageBox.Show(ex.Message);
}
}
private void DisplayCountry()
{
// Create random variable
Random rand = new Random();
// Country us randomly chosen from the list
int countryPosition = rand.Next(countryList.Count);
// Selected country
currentCountry = countryList[countryPosition];
// Show selected country in Label
countryAnswerLabel.Text = currentCountry.countryName;
}
private void ExitButton_Click(object sender, EventArgs e)
{
// Closes the form
this.Close();
}
private void Form1_Load(object sender, EventArgs e)
{
// Call method to load StreamReader with the file
ReadFile();
}
private void QuizButton_Click(object sender, EventArgs e)
{
// Call method to show random country
DisplayCountry();
}
private void CheckAnswerButton_Click(object sender, EventArgs e)
{
// Declare integer variables for the counters and set to 0
int correctCounter = 0;
int incorrectCounter = 0;
// If the input is correct, +1 for the correct counter
if (currentCountry.capital == capitalAnswerTextBox.Text)
{
correctCounter++;
correctLabel.Text = correctCounter.ToString();
}
// If the input is incorrect, +1 for the incorrect counter
else
{
incorrectCounter++;
incorrectLabel.Text = incorrectCounter.ToString();
}
}
private void NextQuestionButton_Click(object sender, EventArgs e)
{
// Clears input TextBox
capitalAnswerTextBox.Text = string.Empty;
DisplayCountry();
}
}
Notice that whenever CheckAnswerButton_Click is executed, the variables correctCounter and incorrectCounter are initialised to 0. So every time you press the button, you start counting the answers from 0 again. So you will always be setting one of label's Text to "1". In case that label already shows "1", it would seem like it's "not doing anything".
Therefore, you should move the declarations of correctCount and incorrectCounter to outside the CheckAnswerButton_Click method:
// Declare integer variables for the counters and set to 0
int correctCounter = 0;
int incorrectCounter = 0;
private void CheckAnswerButton_Click(object sender, EventArgs e)
{
// If the input is correct, +1 for the correct counter
if (currentCountry.capital == capitalAnswerTextBox.Text)
{
correctCounter++;
correctLabel.Text = correctCounter.ToString();
}
// If the input is incorrect, +1 for the incorrect counter
else
{
incorrectCounter++;
incorrectLabel.Text = incorrectCounter.ToString();
}
}
This way, they will retain their value after CheckAnswerButton_Click has returned.
Related
I am creating a Windows Form Application and I want to create a method to be able to pass in a specified text box from a _Click event. Such as below: My Method is AddTo() and I want to call from the 2 click events which have 2 separate text boxes. I want to be able to pass in the correct text box.
void AddTo(string ctrl)
{
int num= int.Parse(ctrl);
num++;
ctrl = num.ToString();
}
private void btnAddLevel_Click(object sender, EventArgs e)
{
AddTo(TextBox1.Text);
}
private void btnAddSecond_Click(object sender, EventArgs e)
{
AddTo(TextBox2.Text);
}
I am pretty new to C#, is this possible to do? Thanks in advance for any help.
UPDATE:
Here is the full code with the fix below
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
txtName.Text = "0";
}
void AddTo(ref TextBox tBox)
{
if (tBox.Text.Trim().Length > 0)
{
int num = 0;
//CHECK IF THE TEXT IS CONVERTIBLE TO NUMBER
if (int.TryParse(tBox.Text, out num))
{
num++;
tBox.Text = num.ToString();
}
}
}
private void btnAddUnit_Click(object sender, EventArgs e)
{
AddTo(ref txtName);
}
}
Use ref key word to retain data updates for passing objects.
Try below code:
//YOUR TEXTBOX IS A REFERNCE HERE. SO THAT THE UPDATES ARE RETAINED
void AddTo(ref TextBox tBox)
{
//VALIDATED YOUR TEXT BOX IF DATA EXISTS BEFORE UPDATING
if (tBox.Text.Trim().Length > 0 )
{
int num = 0;
//CHECK IF THE TEXT IS CONVERTIBLE TO NUMBER
if (int.TryParse(tBox.Text, out num))
{
num++;
tBox.Text = num.ToString();
}
}
}
While calling
//USE REF WHILE CALLING
AddTo(ref textBox1);//textbox object
I'm working on a project and I'm a beginner in programming in c#, and somehow there is a problem that I cannot solve. How it happened: In executing the code, the application launches successfully but an exception
shows that the "Index was outside the bounds of array". Afterwards, I was able to click items on a listbox and it shows the second object on the textbox. So... It seems like it works(clicking on listbox's item) but I cannot figure out why it would throw an exception about the array. Beneath is the current code that I have.
**Update:I sincerely apologize. I uploaded the wrong code. It is suppose to be this code:
Code:
struct studentInfo
{
public string studentID;
public string major;
}
public partial class Form1 : Form
{
private List<studentInfo> studentList = new List<studentInfo>();
public Form1()
{
InitializeComponent();
}
private void ReadInputFile()
{
try
{
StreamReader inputFile;
string line = "";
studentInfo student = new studentInfo();
char[] delimiter = { ',' };
inputFile = File.OpenText("Student Info.txt");
while (!inputFile.EndOfStream)
{
line = inputFile.ReadLine();
string[] token = line.Split(delimiter);
student.studentID = token[0];
student.major = token[1];
studentList.Add(student);
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
private void DisplaystudentID()
{
foreach (studentInfo student in studentList)
{
studentInfoListBox.Items.Add(student.studentID);
}
}
private void DisplayNames()
{
}
private void button1_Click(object sender, EventArgs e)
{
ReadInputFile();
DisplaystudentID();
}
private void studentInfoListBox_SelectedIndexChanged(object sender, EventArgs e)
{
int index = studentInfoListBox.SelectedIndex;
majorTextBox.Text = studentList[index].major;
}
private void button3_Click(object sender, EventArgs e)
{
Application.Exit();
}
}
My guess would be that SelectedIndexChanged is ran at the start (before you select anything) and at that point nameListBox.SelectedIndex would be -1 and you can't get the "negative 1 position's item" in a list. I would make sure that the selected index is valid
https://msdn.microsoft.com/fr-fr/library/system.windows.forms.listbox.selectedindex(v=vs.110).aspx
"A zero-based index of the currently selected item.A value of negative one (-1) is returned if no item is selected."
I would change the code as such:
private void nameListBox_SelectedIndexChanged(object sender, EventArgs e)
{
int index = nameListBox.SelectedIndex;
if(index !=-1)
{
phoneLabel.Text = phoneList[index].phone;
}
// else do nothing, the selected item didn't really change, it's just called for the first time, think of it as the control saying "hey i just got created and i'm notifying you that the selected item is now nothing"
}
You have to guard SelectedIndex, when controls are initially created SelectedIndex is set to -1
private void nameListBox_SelectedIndexChanged(object sender, EventArgs e)
{
if(nameListBox.SelectedIndex >=0)
{
int index = nameListBox.SelectedIndex;
phoneLabel.Text = phoneList[index].phone;
}
}
The only array handling you have in your program is this:
entry.name = tokens[0];
entry.phone = tokens[1];
Therefore the reason is that one of the lines in your text file does not have a comma, so tokens does not have 2 parts.
A common reason for this is simply having a file that has a linefeed after the final real entry, thereby having an empty line as the last line.
I would simply handle this here:
if (tokens.Length < 2)
continue;
You didn't let us know where exactly the exception is occurred but as I see it might be in this part
line = inputFile.ReadLine();
string[] tokens = line.Split(delim);
entry.name = tokens[0];
entry.phone = tokens[1];
If your line is empty or doesn't have "," you will get exception in the next line
Also you need to check the access to list in the index location in nameListBox_SelectedIndexChanged.
"Index was outside the bounds of array" exception occurs when you try to access an element which is not exits in the list. I believe you are getting this exception when you are click on the last item on your list.
In your nameListBox_SelectedIndexChanged method you one of following.
int index = nameListBox.SelectedIndex -1;
or
phoneLabel.Text = phoneList[index-1].phone;
My instructions are: "Create a form that will display a running total of numbers a user enters." - to do this I've created a form with two text boxes (one for the number of values in the array and the other for the values in the array), a button to display it, and a label for it all to be displayed it. The issue is, is that my values aren't showing up - at all. My code is as below:
(** NOTE: I'm attempting to get the array to display in my label. txtInput is the inputted values and txtArrayValues is the number of elements.)
namespace Running_Total
{
public partial class frmEnter : Form
{
public frmEnter()
{
InitializeComponent();
}
private void btnDisplay_Click(object sender, EventArgs e)
{
int intNumber = Convert.ToInt32(txtArrayValues.Text);
string[] strArray;
strArray = new string[intNumber];
int i;
string j = "";
for (i = 0; i < intNumber; i++)
{
j = Convert.ToString(txtInput.Text);
strArray[i] += j;
}
lblDisplay.Text = strArray + " ";
}
}
}
Before, when I'd put lblDisplay.Text += j + " ";, it showed up in the label, but didn't pay any attention to the amount of elements the code was supposed to have. (Edit: this no longer works in my code.) (As is indicated in the title, I'm working with C# through Microsoft Visual Studio.)
It strongly depends on the fashion how the user inputs the numbers.
1) If he fills the textbox once with numbers and then presses the button to display them in the other box, it would suffice to use a string array catch the input and add it to the textbox or label that displays it. If he deletes the numbers in the input box and types new ones you could just repeat this step
namespace Running_Total
{
public partial class frmEnter : Form
{
// declare your Array here
string [] array = new string[1000];
int count = 0;
public frmEnter()
{
InitializeComponent();
}
private void btnDisplay_Click(object sender, EventArgs e)
{
// save input
array[count] = inputTextBox.Text;
count++;
// display whole input
string output = "";
for(int i = 0;i < count; i++)
{
output += array[i];
}
// write it the texbox
outputTextBox.Text = output;
}
}
Does that answer your question or do you have another input pattern in mind?
Looking at your code, I realized that you want to display same number enteted in txtInput text repeatedly up to as many times as a number entered in a txtArrayValues.Text. So for example txtArrayValues. Text = "5" and txtInput.Text="2", your code will yield result "2,2,2,2,2". If that is what you want then the following code will achieve that.
using System.Linq;
namespace Running_Total
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void btnDisplay_Click(object sender, EventArgs e)
{
int len, num;
if (int.TryParse(txtArrayValues.Text, out len) &&
int.TryParse(txtInput.Text, out num))
{
lblDisplay.Text = string.Join(",", new string[len].Select(x => txtInput.Text));
}
}
}
}
So I have a label called lblScore.Text and lblScore.Text = iCorrectACount.ToString(); where iCorrectACount is basically a counter of how many questions a user answered right. Now what I want to do is basically make it so that this number multiplies the end score depending on the difficulty chosen i.e. if easy questions are chosen, multiply iCorrectACount by 0 and cast to string, if medium questions are chosen, multiply iCorrectACount by 1.5 and cast to string and if hard questions are chosen, multiply iCorrectACount by 2 and cast to string, but I'm not sure how I'd do this.
My code is like this:
private void QuizReset()
{
// Resets the difficulty selection control and shows it again upon resetting the quiz
difficultySelectionControl.Reset();
difficultySelectionControl.BringToFront();
// Disabled the 'Next' button and prompts the user to select a difficulty - User cannot continue without choosing
btnNext.Enabled = false;
lblStatus.Text = "Please select a difficulty";
// Sets the number of questions and correct answers to zero
iCorrectACount = 0;
iCurrentQIndex = 0;
}
private void LoadQuestions(Difficulty difficulty)
{
// Defines a random variable to be used to shuffle the order of the questions and answers
var rand = new Random();
// Loads the corresponding XML document with 'Easy', 'Medium' or 'Hard' questions depending on difficulty chosen
var xdoc = XDocument.Load(GetFileNameFor(difficulty));
// List of questions that are filtered from the XML file based on them being wrapped in question tags
_questions = xdoc.Descendants("question")
.Select(q => new Question()
{
ID = (int)q.Attribute("id"),
Difficulty = (int)q.Attribute("difficulty"),
QuestionText = (string)q.Element("text"),
Answers = q.Element("answers")
.Descendants()
// Stores all answers into a string
.Select(a => (string)a)
// Randomizing answers
.OrderBy(a => rand.Next())
.ToArray(),
CorrectAnswer = (string)q.Element("answers")
.Descendants("correctAnswer")
// Use value instead of index
.First()
})
// Selects questions that match the difficulty integer of the option the user chose
.Where(q => q.Difficulty == (int)difficulty + 1)
// Randomizing questions
.OrderBy(q => rand.Next())
.ToList();
lblStatus.Text = String.Format("There are {0} questions in this section", _questions.Count);
}
private string GetFileNameFor(Difficulty difficulty)
{
switch (difficulty)
{
case Difficulty.Easy: return "quiz_easy.xml";
case Difficulty.Medium: return "quiz_medium.xml";
case Difficulty.Hard: return "quiz_hard.xml";
default:
throw new ArgumentException();
}
}
private void PickQuestion()
{
questionControl.DisplayQuestion(_questions[iCurrentQIndex]);
questionControl.BringToFront();
iCurrentQIndex++;
}
private void FormMain_Load(object sender, EventArgs e)
{
QuizReset();
lblScore.Text = "0";
}
private void miNewQuiz_Click(object sender, EventArgs e)
{
QuizReset();
lblScore.Text = "0";
}
private void miExit_Click(object sender, EventArgs e)
{
Close();
}
private void miHelp_Click(object sender, EventArgs e)
{
FormHowToPlay form = new FormHowToPlay();
form.ShowDialog();
}
private void miAbout_Click(object sender, EventArgs e)
{
AboutBox1 aboutForm = new AboutBox1();
aboutForm.ShowDialog();
}
private void btnNext_Click(object sender, EventArgs e)
{
if (iCurrentQIndex < _questions.Count)
{
PickQuestion();
lblStatus.Text = String.Format("Question {0} of {1}", iCurrentQIndex, _questions.Count);
}
else
{
btnNext.Enabled = false;
lblStatus.Text = String.Format("You answered {0} questions correctly out of a possible {1}",
iCorrectACount, _questions.Count);
this.Hide();
SummaryForm sumForm = new SummaryForm();
DialogResult result = sumForm.ShowDialog();
MenuForm mnuform = new MenuForm();
mnuform.ShowDialog();
}
}
private void difficultySelectionControl_DifficultySelected(object sender, DifficultySelectedEventArgs e)
{
iCurrentQIndex = 0;
LoadQuestions(e.Difficulty);
btnNext.Enabled = true;
}
private void questionControl_QuestionAnswered(object sender, QuestionAnsweredEventArgs e)
{
if (e.IsCorrect)
iCorrectACount++;
lblScore.Text = iCorrectACount.ToString();
}
It's the last little thing I need to figure out and I can't figure out how to get it so that if the difficulty = easy/medium/hard, multiply iCorrectAmount by 1/1.5/2/0.
Thanks for any help or advice.
Just do this:
int modifier = 1;
if (difficulty == Difficulty.Medium) { modifier = 1.5; }
if (difficulty == Difficulty.Hard) { modifier = 2; }
lblScore.Text = (iCorrectACount * modifier).ToString();
you'll need to get the difficulty from somewhere obviously, and I can't tell where exactly right now, but you have it because you passed it into the method LoadQuestions and GetFileNameFor, so just grab it, run the code, and BAM you got your modifier.
NOTE: I set the modifier to 1 by default, I'm pretty sure you didn't want to set it to 0 since that would net 0 as the result every time.
in difficultySelectionControl_DifficultySelected, store the selected difficulty in a class variable, m_difficulty.
Then, just access it in questionControl_QuestionAnswered
in your class definition, add private Difficulty m_difficulty.
in difficultySelectionControl_DifficultySelected, add a line saying m_difficulty = e.Difficulty.
then, you can use that difficulty in your questionControl_QuestionAnswered, just like #Michael Perrenoud suggested.
I need help with timer and List.
List consist of collection of string say 5 or 6 at a time. Now, I want to display string one on label1 and it should wait for 5s and then display string 2 on label1. I have timer control and I am specifying my code in timer_tick event.
private void timer1_Tick(object sender, EventArgs e)
{
string[] myStatus = myStatusCollection.ToArray();
int length = myStatus.Length;
for (int i = 0; i < length; i++)
{
string _myStatus = myStatus[i];
//label1.ResetText();
MessageBox.Show("Twitter Status =" + _myStatus);
//label1.Text = _myStatus;
//label1.Visible = true;
}
}
I have specify, Elapse = true and interval = 5000 but still I am not able to display one string at a time. In fact, I am getting last string only. I want to rotate the strings all time.
Can anyone help me.
That's because you're looping through all the strings each time the timer event fires.
Store your index in a private variable and use that instead.
private int _index = 0;
private void timer1_Tick(object sender, EventArgs e)
{
string[] myStatus = myStatusCollection.ToArray();
string _myStatus = myStatus[_index];
//label1.ResetText();
MessageBox.Show("Twitter Status =" + _myStatus);
//label1.Text = _myStatus;
//label1.Visible = true;
if(_index == (myStatus.Length - 1))
_index = 0;
else
_index++;
}
Well it is doing just what you told it to. However, what you told it to do is not what you meant for it to do. Try this.
public class Form1 : Form {
private string[] statuses = { "A", "B", "C", "D", "E" }; // Init with proper values somewhere
private int index = 0;
private void OnTimerTick(object sender, EventArgs e) {
string status = statuses[index];
index++;
if (index == statuses.Length) { // If index = Array.Length means we're
// outside bounds of array
index = 0;
}
}
}
I'd create an int outside of the Tick to hold your position. Make sure you reset it back to 0 when you restart the process.
int MyPosition = 0;
private void timer1_Tick(object sender, EventArgs e)
{
string[] myStatus = myStatusCollection.ToArray();
int length = myStatus.Length;
if((MyPosition + 1) > length)
{
//Index Out of Range
}
else
{
string _myStatus = myStatus[MyPosition];
label1.Text = _myStatus
}
MyPosition++;
}