Having track of actions done by a button
Dear Friends,
I want to write a simple program which will allow user to only do something for limited times (which will be hard coded in to the program).
I have a TextBox and two Save buttons. I also have a third button which is named Start. if user click on Start then he can start entering a text into TextBox and save the text in two different files and he can do that n times which n is hard coded into program.
But I don't know what will the best way to do this. I am thinking of events but I can not figure it out myself so I really need your help. Here is the code I managed to write but it does not work for reasons I want to know from you!
Code:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
int save1 = 0;
int save2 = 0;
System.IO.StreamWriter file1 = new System.IO.StreamWriter("c:\\test1.txt");
System.IO.StreamWriter file2 = new System.IO.StreamWriter("c:\\test2.txt");
private void buttonSave1_Click(object sender, EventArgs e)
{
file1.WriteLine(textBox1.Text);
save1++;
}
private void buttonSave2_Click(object sender, EventArgs e)
{
file2.WriteLine(textBox1.Text);
save2++;
}
private void buttonStart_Click(object sender, EventArgs e)
{
int i = 3;
while (i >= 0)
{
switch (i)
{
case (3):
this.label1.Text = "Saved 0 of 3";
if (save1 == 0 && save2 == 0)
{
this.label1.Text = "Saved 1 of 3";
}
i--;
break;
case (2):
if (save1 == 1 && save2 == 1)
{
this.label1.Text = "Saved 2 of 3";
}
i--;
break;
case (1):
if (save1 == 2 && save2 == 2)
{
this.label1.Text = "Saved 3 of 3";
}
i = 0;
file1.Close();
file2.Close();
break;
}
}
}
}
}
Re: Having track of actions done by a button
This appears to be a homework-type question, so I won't tell you outright, but you appear to be well on the right track. I will give you this hint though: every time you enter buttonStart_Click, you reset the value of i to 3. Is this the behavior you want? (Hint: no).
Can you see how to fix it now?
Re: Having track of actions done by a button
omg it is not a home work :D I am trying to make an automatic server configurator for crysis (MWLL).
Well the problem is as soon as I click on start, the program freezes and I cant even click on Save1 and Save2 buttons or even write someting in the textbox.
what I want is that by clicking on START, a loop will be started (for ex. 3 loops required) and each time that save1 and save2 are clicked (both need to be clicked) the loop will finish one of the loops! and after for example 3 lines has been entered in each file (that is 3 in test1.txt and test2.txt and totaly 6 clicks on save1 and save2) the loop is finished.
so the idea is user hits SAVE only 1 time, then he has to write some code in texbox and save them then again repeat this until the loop is finished.
I tried to move out that int i = 3; out of button event but still cant figure this out.
Re: Having track of actions done by a button
Well, I think BioPhys assumed it was homework due to the... odd behavior you are going for and the fact that it doesn't look like something you would see in a "professional" (for lack of a better term) code base. Why would you limit the number of times the user can save a file? What is to be accomplished by doing that?
Anyways, your application hangs because it is stuck inside of a while loop. Walk through it in your head:
First iteration: i == 3, first case is executed. i is decremented.
Second iteration: i == 2, second case is executed. i is decremented.
Third iteration: i == 1, third case is executed. i is set to zero and the loop never exits because i is never modified again and the condition is i >= 0, which is still true. This is an endless loop.
Typically you would use a for loop (as opposed to a while loop) when the number of iterations is known.
Code:
for( int i = 0; i < 3; ++i )
{
// code
}
Even still, the loop is meaningless since all cases will be executed in serial anyway, and you won't see your UI updates because you are clogging the message pump while you are inside of that loop. Only the last update will be seen by the user. You may as well just remove the first two cases and execute the third one unconditionally.
Re: Having track of actions done by a button
I tried to fix the START loop as follow:
Code:
private void buttonStart_Click(object sender, EventArgs e)
{
int i = 3;
while (i > 0)
{
if (save1 == 1 && save2 == 1) i--;
if (save1 == 2 && save2 == 2) i--;
if (save1 == 3 && save2 == 3) { i = -1; }
}
}
But the problem still exist, when I click the START button to start writing in the textbox and saving to file using button1 and 2, the program freezes and it does not allow me to enter any text in the textbox and clicking on other buttons.
I think I am not on the right track. this kind of problem should be treated with events? how? need help please!
Thanks.
Re: Having track of actions done by a button
Ok, first, learn to use the debugger. Step through your code and watch what it does. Second, you still have an endless loop if those first two conditions are not met. I'm still not sure what you are trying to accomplish with code like this.
Re: Having track of actions done by a button
OK, so I have no idea what you're trying to do but anyway you need a Default or an else. As everyone has been mentioning you have an infinite loop and you need a way out especially if your conditions have not been met.
Code:
private void buttonStart_Click(object sender, EventArgs e)
{
int i = 3;
while (i > 0)
{
if (save1 == 1 && save2 == 1)
{
i--;
}
else if (save1 == 2 && save2 == 2)
{
i--;
}
else if (save1 == 3 && save2 == 3)
{
i = -1;
}
else
{
i = -1;
}
}
}
or
Code:
private void buttonStart_Click(object sender, EventArgs e)
{
int i = 3;
while (i >= 0)
{
switch (i)
{
case (3):
this.label1.Text = "Saved 0 of 3";
if (save1 == 0 && save2 == 0)
{
this.label1.Text = "Saved 1 of 3";
}
i--;
break;
case (2):
if (save1 == 1 && save2 == 1)
{
this.label1.Text = "Saved 2 of 3";
}
i--;
break;
case (1):
if (save1 == 2 && save2 == 2)
{
this.label1.Text = "Saved 3 of 3";
}
i = -1;
file1.Close();
file2.Close();
break;
default:
i = -1;
file1.Close();
file2.Close();
}
}
}
...also get out of the habit of writing inline if's and else's. They are bad for debugging and take it from someone who works on legacy code bases, they are not easily readable nor easily debugged...
Re: Having track of actions done by a button
Ok guys!
First thanks for your time spending on my problem.
Second here is the situation:
http://i54.tinypic.com/9tmkut.jpg
As you can see I have two save buttons which are disabled, when I click on START button these two save buttons will be enabled and I want user to enter a text in that textbox and hit save1 and save2, then he can change the text and hit again save1 and save2...each save will inrease the counter for it that is for example save1++
I want user to be able to only save 3 lines in each file. I tried the debug but I could not understand it!
Re: Having track of actions done by a button
I tried the Demons approach but it seems it always takes the default the case, even when I deleted default section of the switch it also shows me "Cannot write to a closed TextWriter"
Re: Having track of actions done by a button
Most likely because of your cases: "if (save1 == 2 && save2 == 2)". If save1 and save2 are not equal then it will always hit the default/else. I'd use "if (save1 == 2 || save2 == 2)" meaning that if save1 or save2 equals '2'.
The other issue is because you never 'opened' (used) the textwriter so you can't close it. I just copied and pasted so that is more my fault.
Re: Having track of actions done by a button
well. I opened the file writer at the begining of the program using
Code:
System.IO.StreamWriter file1 = new System.IO.StreamWriter("c:\\test1.txt");
System.IO.StreamWriter file2 = new System.IO.StreamWriter("c:\\test2.txt");
I am suspisious that WHILE or FOR will not make this possible...
Re: Having track of actions done by a button
Don't close the StreamWriter until you are completely finished or in your button events use "file1 = new System.IO.StreamWriter("c:\\test1.txt");" before writing your text. When you close the StreamWriter it is similar to "Dispose" and basically throws aways the writer.
I found a quick simple article on StreamWriters (I don't know much about StreamWriter).
Or just close it after using it like this below:
Code:
System.IO.StreamWriter file1;
System.IO.StreamWriter file2;
private void buttonSave1_Click(object sender, EventArgs e)
{
file1 = new System.IO.StreamWriter("c:\\test1.txt");
file1.WriteLine(textBox1.Text);
file1.close();
save1++;
}
private void buttonSave2_Click(object sender, EventArgs e)
{
file2 = new System.IO.StreamWriter("c:\\test2.txt");
file2.WriteLine(textBox1.Text);
file2.close();
save2++;
}
Re: Having track of actions done by a button
I guess the problem is not about stream writers, it is about the while loop cant have track of my counter for save buttons, there should be some other way...I am thinking of event handling..would be nice if you guys give more comments.
Re: Having track of actions done by a button
Why not add a check to the save buttons themselves?
Code:
int i = 3;
private void buttonSave1_Click(object sender, EventArgs e)
{
if(save1 >= i)
{
file1 = new System.IO.StreamWriter("c:\\test1.txt");
file1.WriteLine(textBox1.Text);
file1.close();
save1++;
}
}
Your entire start button handler doesn't make a lot of sense to me so it's hard to tell what you're trying to do. If you want more comments you need to provide a better description of what you are trying to do at least in that section... Checking to see if the user clicked the save buttons the same number of times means that you need to add a check somewhere that the user did click those buttons the same number of times. And I just gave you why you were getting "Cannot write to a closed TextWriter" and I pointed you to an article that better explains it...
Re: Having track of actions done by a button
Oops... sorry for leading you astray! I guess I was reading through your code too quickly and missed the while loop. >___<
Re: Having track of actions done by a button
NOOOOO it is very very important that user just be able to add 3 lines to the text files. and if you saw my program picture in here :
http://[img]http://forums.codeguru.c....jpg[/img]
When the form starts, save1 and save2 button Enabled property is set to false so user cant do something. As soon as he click on start, then those save buttons will be enabled and user can enter a text in textbox and save it in text files using those buttons maximum 3 times. AND THIS 3 times just is a example it could be less or more. after the saving is done, the buttons will be disabled again!
I know I dont need the start button,,,but lets see this as a fight with the code and insist on precense of the start button.
OMG is this that hard :( :(
Re: Having track of actions done by a button
1. I think you've misread what I've posted...
2. I get what your intent is here but you're going about it in an odd way. I get you're trying to allow the user to write to a file 3 times but at no point in your application are you allowing the user to do anything. The code is sequential so once you've enabled the save buttons you then enter a while loop that runs infinitely because save1 and save2 forever equal '0'. The while loop and its checks need to be moved out of start and into its own method. You can achieve something closer to your intended 'event handler' solution if you move everything inside the while loop into a thread.
3. I've rewritten what you've posted to something that works at least close to what you're trying to get at here. Again one issue that you are having is that you have to make sure that save1 and save2 are equal because if I the user hit buttonSave1 4 times and buttonSave2 once then save1=4 while save2=1 and at no point in time will they ever equal 3.
Code:
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
//--- Number of saves
int save1 = 0; // Counter for buttonSave1
int save2 = 0; // Counter for buttonSave2
//--- Maximum number of saves allowed
int max = 3;
//Note: changed 'i' to max because its easier to read that way
System.IO.StreamWriter file1;
System.IO.StreamWriter file2;
public Form1()
{
InitializeComponent();
//--- Initialize save buttons to false
buttonSave1.enabled = false;
buttonSave2.enabled = false;
this.label3.Text = "0";
this.label4.Text = "0";
}
//--- Check the number of saves
private void CheckSaves()
{
//--- Make sure that both values are the same
if(save1 == save2)
{
//--- Since both saves are equal we only need to check one of them not both
if(save1 == 1)
{
//--- Decrement
max--;
}
else if(save1 == 2)
{
//--- Decrement
max--;
}
else if(save1 == 3)
{
//--- Decrement
max--;
//--- Reset values
save1 = 0;
save2 = 0;
//You can put 'file1.close();' and 'file2.close();' here but you need to remove it in the handlers...
}
}
else //--- Else save1 and save2 are not equal and we should make sure that they do not save more than the maximum amount
{
//--- if either save1 or save2 have hit the max then do not allow the user to keep saving
if(save1 == max)
{
//--- disable the save so that we don't go past the max
buttonSave1.enable = false;
}
else if(save2 == max)
{
//--- disable the save so that we don't go past the max
buttonSave2.enable = false;
}
}
}
//--- ButtonSave1's event handler
private void buttonSave1_Click(object sender, EventArgs e)
{
//--- If we are over the limit for the number of saves then do not allow another write to happen
if(save1 <= max)
{
//Note: this should be within a Try/Catch block
//--- ensure that we correctly open the stream writer
file1 = new System.IO.StreamWriter("c:\\test1.txt");
//--- write stream to text
file1.WriteLine(textBox1.Text);
//--- close writer
file1.close();
//--- increment number of saves
save1++;
//--- Display current number of saves
this.label3.Text = "Save " + save1.ToString() + " of " + max.ToString();
}
//--- determine if we have hit the mazimum
CheckSaves();
}
//--- ButtonSave2's event handler
private void buttonSave2_Click(object sender, EventArgs e)
{
//--- If we are over the limit for the number of saves then do not allow another write to happen
if(save1 <= max)
{
//Note: this should be within a Try/Catch block
//--- ensure that we correctly open the stream writer
file2 = new System.IO.StreamWriter("c:\\test2.txt");
//--- write stream to text
file2.WriteLine(textBox1.Text);
//--- close writer
file2.close();
//--- increment number of saves
save2++;
//--- Display current number of saves
this.label3.Text = "Save " + save2.ToString() + " of " + max.ToString();
}
//--- determine if we have hit the mazimum
CheckSaves();
}
private void buttonStart_Click(object sender, EventArgs e)
{
//--- Turn save buttons on
buttonSave1.enabled = true;
buttonSave2.enabled = true;
}
}
}
Re: Having track of actions done by a button
Thanks, this work a little bit like I want, but still cant do the job. I am trying to fix it since yesterday but got me to no where yet.
Re: Having track of actions done by a button
I just whipped this up in about five minutes - is this what you're trying to do?
Code:
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 SaveLines
{
public partial class Form1 : Form
{
private int save1 = 0;
private int save2 = 0;
private string file1 = "";
private string file2 = "";
public Form1()
{
InitializeComponent();
btnSave1.Enabled = false;
btnSave2.Enabled = false;
label1.Text = "File 1: 0";
label2.Text = "File 2: 0";
}
private void btnStart_Click(object sender, EventArgs e)
{
btnSave1.Enabled = true;
btnSave2.Enabled = true;
}
private void btnSave1_Click(object sender, EventArgs e)
{
file1 += textBox1.Text;
save1++;
label1.Text = "File 1: " + save1;
if (save1 >= 3)
btnSave1.Enabled = false;
else
file1 += Environment.NewLine;
File.WriteAllText("text1.txt", file1);
}
private void btnSave2_Click(object sender, EventArgs e)
{
file2 += textBox1.Text;
save2++;
label2.Text = "File 2: " + save2;
if (save2 >= 3)
btnSave2.Enabled = false;
else
file2 += Environment.NewLine;
File.WriteAllText("text2.txt", file2);
}
}
}