My program requires users to input answers into a text box to randomly generated questions. The questions have calculated answers which are stored in variables. Comparing the text box's input with that variable doesn't work properly, hence why I'm here.
enum elements { lithium, beryllium, sodium, magnesium };
public void Moles()
{
string elementName;
int elementsLength = Enum.GetNames(typeof(elements)).Length;
double moles, mass, roundedMoles, Mr = 0;
Random random = new Random();
elementName = (Enum.GetNames(typeof(elements))[random.Next(0, elementsLength)]);
mass = random.Next(1, 100);
switch (elementName)
{
case "lithium":
Mr = 7;
break;
case "beryllium":
Mr = 9;
break;
case "sodium":
Mr = 23;
break;
case "magnesium":
Mr = 24;
break;
}
moles = mass / Mr;
roundedMoles = Math.Round(moles);
label1.Text = ("How many moles in " + mass + "g" + " of " + elementName + "?");
string input = textBox1.Text.ToString();
if (input == roundedMoles.ToString())
{
MessageBox.Show("Good");
textBox1.Clear();
}
else
{
MessageBox.Show("Bad");
textBox1.Clear();
}
private void button1_Click(object sender, EventArgs e)
{
Moles();
}
As you can see, the program will calculate a number of moles and round it to the nearest whole number. It's then stored in a variable, 'roundedMoles' - this variable is what's compared with the text box's input.
However, the message box will randomly show 'Good' or 'Bad' regardless of whether the input is correct or not. Bear in mind that this code works fine in a console application, so I don't know whether it's something I'm doing wrong or if it just doesn't want to work.
Sorry if this code isn't of a high standard. I'm not that good at programming.
You have two problems.
Don't compare strings as numbers
When comparing numeric values, never compare string to string. Always convert to a numeric variable. Otherwise, "0.00" will not equal "0" and "1234 " (with a space at the end) won't equal "1234" (with no space). Also, you will run into serious trouble if you're working with a culture that uses , as the decimal point.
So, instead of this:
string input = textBox1.Text.ToString();
if (input == roundedMoles.ToString())
{
MessageBox.Show("Good");
textBox1.Clear();
Use something like this:
string input = textBox1.Text;
double inputAsDouble;
bool ok = double.tryParse(out inputAsDouble);
if (!ok)
{
MessageBox.Show("Please enter a numeric value.");
return;
}
if (inputAsDouble == roundedMoles)
{
MessageBox.Show("Good");
textBox1.Clear();
Don't compare floating point values as exact
When comparing floating point values, don't use ==. Instead, compute the difference and make sure it is below a certain tolerance. You have to do this because floating point variables are only approximations.
So instead of
if (inputAsDouble == roundedMoles)
use
const double Tolerance = 0.00001;
if (inputAsDouble - roundedMoles < Tolerance)
Ok so here is the answer...
The reason the console works is that you write to the console to ask the question. You then do console.Readline() this captures the input of the answer after they have seen the question.
On the forms version. You set the label to the question and immediately capture the text box value. The user has not had a chance to enter the answer, or its still the answer from the last time (hence why it randomly goes from "Good" to "Bad" because sometimes the answer is the same).
One simple way is make your variables at the top of the Moles() method, class variables on the form and then have 2 buttons with 2 methods one that gets the questions and sets your answer variables and then a second button then the user can press when they've entered their answer.
Check out this code paste https://www.pastebucket.com/564406
(You'll need button2 added to your form for this to work obviously)
edit: I've done a quick cut and paste of code there. You shouldn't just copy this and use it. Look what I've done and apply it properly and try and understand why it works
It seems that you might have a culture related problem down there. Always be careful when comparing Double values converted to String. The framework might be converting '1,5' to '1.5' depending on your regional settings.
The first thing I would recomend you is not to compare as String but do it as Double. And if you do that, ensure that you will replace dots with comma or other way.
if (Convert.ToDouble(input) == roundedMoles)
{
MessageBox.Show("Good");
textBox1.Clear();
}
else
{
MessageBox.Show("Bad");
textBox1.Clear();
}
Related
I'm attempting to create a wpf app that takes a list of numerical values, separated by line breaks, in one textbox. You click a button, and it outputs the new numerical values into a second textbox. I'm running into issues separating the values the user inputs.
For this to make more sense the first textbox is called inputBox and the second textbox is called outputBox. The button will have event mathClick. We will have the button just multiply the number by 2.
This is what I have:
private void mathClick(object sender, RoutedEventArgs e)
{
foreach (var num in inputBox.Text.Split("\n"))
{
if(double.TryParse(num, out double value))
{
outputBox.Text = Convert.ToString(value * 2);
}
}
}
This is what happens
inputBox:
7.02
18.98
3.51
outputBox:
7.02
It's only grabbing the last value in the textbox and doing the arithmetic on that.
This is the scenario I'm trying to achieve
inputBox:
7.02
18.98
3.51
outputBox:
14.04
37.96
7.02
Any help is greatly appreciated.
I figured it out, if any other beginners like me come across this - you must remember Textbox will return a string. The way I fixed it was to split the input at the linebreak and store it in a string array
string[] stringNum = textbox.text.split("\n");
Then you can use a for loop to convert this array of type string to a double and print the double to your textbox with a linebreak each time the loop runs.
for (int i = 0; i < stringNum.Length; i++)
{
double num = Convert.ToDouble(stringNum[i]);
textbox.text += Convert.ToString($"{num}\n");
}
Hope this helps someone else, thanks.
Here is the right example
Need to use int data types.
SO, I am able to enter a number and but I get duplicate of a just one number.
Here is what I get on my code:
//create a string for the name
string name = txtName.Text;
// create a int for the number
// have those now have to get three amounts
// for each name then store that
// make a size three array
//innt to put the array in the for loop
int[] x = new int[3];
for (int i = 0; i < x.Length; i++)
{
//txtScore.Text
//txtStoreScores.Text
int covert = Int32.Parse(txtScore.Text);
x[i] = covert;
txtStoreScores.AppendText(x[i].ToString());
// ok I just need one number
// and split them by each number
}
Honestly, though you have selected an answer this feedback may be beneficial to future solutions. Your button once triggered should fire an event, inside that could you want to ensure you properly sanitize user input. Assume the user will cause an error, because the amount of variables they can input are infinite.
protected void btnAddScore_Click(object sender, EventArgs e)
{
if(float.TryParse(txtGrade.Text, out grade) && grade >= 0)
txtScores.Text += $"{grade}, ";
}
That simple conditional will sanitize, by ensuring that the user has entered a valid numeric and the score is higher than zero. Especially since a negative number would be unlikely. The primary point, your code should reflect the usage. Your code should account for those anomalies and variances that may occur.
Another nifty notion, you are outputting directly based on input. When you save that information, you would need to parse the data. So realize that you may need to something along these lines:
var scores = txtScores.Text.Split(','); // An array.
txtScores.Text = String.Join(",", scores); // Converts array into single string
The problem will increase in complexity over time, so be aware of that. Hopefully this was helpful. As for your math, if you do the following it would calculate:
var sum = txtScores.Text.Split(", ").Sum(grade => (float)grade);
The above makes a potentially flawed assumption, that all would cast to a float without an issue. These are items you need to think about. If you do not cast then your sum would be reflected by the length of your string not the values.
if i understand this right!!! you want to append the number from txtScore to txtStoreScores each time you click Add Scores btn!!!!
in this case you don't need a loop, simply put this in Add Scores btn event handler
txtStoreScores.Text += txtScore.Text + " ";
you reaaaaaly need to give more details and a clear question. Good luck!
I am trying to build a help function in my guess the number game, whereby the user gets the first digit of the number he/she has to guess. So if the generated number is 550, he will get the 5.
I have tried a lot of things, maybe one of you has an idea what is wrong?
public partial class Class3
{
public Class3()
{
double test = Convert.ToDouble(globalVariableNumber.number);
while (test > 10)
{
double firstDigit = test / 10;
test = Math.Round(test);
globalVariableNumber.helpMe = Convert.ToString(firstDigit);
}
}
}
Under the helpButton clicked I have:
private void helpButton_Click(object sender, EventArgs e)
{
label3.Text = globalVariableNumber.helpMe;
label3.AutoSize = true;
That is my latest try, I putted all of this in a custom class. In the main I putted the code to show what is in the helpMe string.
If you need more code please tell me
Why not ToString the number and use Substring to get the first character?
var number = 550;
var result = number.ToString().Substring(0, 1);
If for some reason you dont want to use string manipulation you could do this mathematically like this
var number = 550;
var result = Math.Floor(number / Math.Pow(10, Math.Floor(Math.Log10(number))));
What's wrong - you have an infinite while loop there. Math.Round(test) will leave the value of test unchanged after the first iteration.
You may have intended to use firstDigit as the variable controlling the loop.
Anyway, as suggested by others, you can set helpMe to the first digit by converting to a string and using the first character.
As an aside, you should consider supplying the number as a parameter and returning the helpMe string from the method. Your current approach is a little brittle.
The problem with your code is that you are doing the division and storing that in a separate variable, then you round the original value. That means that the original value only changes in the first iteration of the loop (and is only rounded, not divided), and unless that happens to make the loop condition false (i.e. for values between 10 and 10.5), the loop will never end.
Changes:
Use an int intead of a double, that gets you away from a whole bunch of potential precision problems.
Use the >= operator rather than >. If you get the value 10 then you want the loop to go on for another iteration to get a single digit.
You would use Math.Floor instead of Math.Round as you don't want the first digit to be rounded up, i.e. getting the first digit for 460 as 5. However, if you are using an integer then the division truncates the result, so there is no need to do any rounding at all.
Divide the value and store it back into the same variable.
Use the value after the loop, there is no point in updating it while you still have multiple digits in the variable.
Code:
int test = (int)globalVariableNumber.number;
while (test >= 10) {
test = test / 10;
}
globalVariableNumber.helpMe = test.ToString();
By using Math.Round(), in your example, you're rounding 5.5 to 6 (it's the even integer per the documentation). Use Math.Floor instead, this will drop the decimal point but give you the number you're expecting for this test.
i.e.
double test = Convert.ToDouble(globalVariableNumber.number);
while (test > 10)
{
test = Math.Floor(test / 10);
globalVariableNumber.helpMe = Convert.ToString(firstDigit);
}
Like #Sam Greenhalgh mentions, though, returning the first character of the number as a string will be cleaner, quicker and easier.
globalVariableNumber.helpMe = test >= 10
? test.ToString().SubString(0, 1)
: "Hint not possible, number is less than ten"
This assumes that helpMe is a string.
Per our discussion in the comments, you'd be better off doing it like this:
private void helpButton_Click(object sender, EventArgs e)
{
label3.Text = GetHelpText();
label3.AutoSize = true;
}
// Always good practice to name a method that returns something Get...
// Also good practice to give it a descriptive name.
private string GetHelpText()
{
return test >= 10 // The ?: operator just means if the first part is true...
? test.ToString().SubString(0, 1) // use this, otherwise...
: "Hint not possible, number is less than ten" // use this.
}
i created a win-form with an ability to generate a number with 3 labels(label1,label2,label4) and a textbox that will be storage and then validate its value when ever the button is pressed. my problem is that the label4 didn't raise its own value when ever i answer it correctly.
with this code
int num = 0;
string temp;
if (textBox1.Text == ans.ToString())
{
num++;
temp = "Correct Answers " + num;
int a = rr.Next(4), b = rr.Next(4);
ans = a + b;
label1.Text = a.ToString();
label2.Text = b.ToString();
label4.Text = temp;
textBox1.Focus();
textBox1.SelectAll();
}
Does label4 never increase its own value, or does it never increase it more than the first time? Because the latter of those two options is exactly what you're doing. Look at the steps in your logic:
int num = 0;
string temp;
//...
num++;
temp = "Correct Answers " + num;
//...
label4.Text = temp;
No matter how many times you answer correctly, label4 can only ever display:
"Correct Answers 1"
Because you always initialize num to 0, increment it to 1, and display it. Where do you track how many answers have been given in total?
You'll need some integer value in a higher scope to track that. Where you place it depends on the lifespans of your objects. For example, if the object in which this logic exists persists across multiple answers (that is, if the same instance is always in memory and it's not destroyed and re-created), then you can add a class-level member to hold that value. Something like this:
private int TotalCorrectAnswers { get; set; }
Then your code would use that value instead of instantiating a new one each time:
string temp;
//...
TotalCorrectAnswers++;
temp = "Correct Answers " + TotalCorrectAnswers;
//...
label4.Text = temp;
Other options could include storing the value in a static field to persist across object life cycles, a database to persist across application life cycles, etc. It depends on how your application is structured.
So when you provide an answer to the math problem, the highest your Label4 that indicates correct answers counts is 1? You aren't by chance defining the variable num within your click event handler are you? In this case every time you got an answer correct it would increment num from zero to one, incorrect would show no change, but then your next correct answer would again increment from zero to one.
I have some textboxes in my form. I wrote the code on leave event to add 0.00 automatically. I wrote the code to add two textboxes value to the third one as
try
{
decimal netVal = 0;
decimal.TryParse(txtNetValue.Text, out netVal);
decimal disc2 = 0;
decimal.TryParse(txtDisc2.Text, out disc2);
decimal tax1 = 0;
decimal.TryParse(txtTax1.Text, out tax1);
decimal tax = netVal - disc2;
string strtax = ((tax / 100) * tax1).ToString();
txtTax2.Text = strtax.Substring(0, strtax.IndexOf(".") + 3);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
In this case when I click the new button to clear all the controls I am getting an exception as Index and length must refer to a location within the string. Parameter name: length.
Your issue is here:
strtax.Substring(0, strtax.IndexOf(".") + 3);
I don't believe that Substring does what you think it does. The arguments are not "startIndex" and "endIndex" (Beginning and End), they are "startIndex" and "Length" (Beginning and length of substring). Most likely, this confusion is causing you to attempt to get a substring that is larger than the size of the string.
For example, you're saying I want the last 10 characters of "Test". "Test" only has four characters, so trying to get the "last ten" will cause that error.
It looks like your end goal is to have the value formatted as money. If this is the case then you can use the handy Decimal.ToString("C"). There are many other formats that you may want instead, see this link for more info on formatting.