I'm trying to write a simple program to check battery status. I have a timer which ticks every second and I wrote some code, but I think it is not most effective.
1. I don't know if is the way, how I to check if is a percentage of battery is same as one second before, is right.
2. If I don't check MsgBox then percentage info in Label2 and MsgBox texts are not updated.
class Battery
{
public static int BatteryPercentage()
{
PowerStatus ps = SystemInformation.PowerStatus;
int percentage = Convert.ToInt32(ps.BatteryLifePercent * 100);
return percentage;
}
}
public static class MyClass
{
public static int LastPer { get; set; }
}
private void timer1_Tick(object sender, EventArgs e)
{
int per = Battery.BatteryPercentage();
label2.Text = per.ToString();
progressBar1.Value = per;
if (MyClass.LastPer == 0)
{
MyClass.LastPer = per;
}
else if (MyClass.LastPer > per && per <= 100)
{
MessageBox.Show("Battery is almost empty, remain " + per.ToString() + "!" );
}
}
I think it would be more efficient to get rid of your timer and subscribe to the report updated event of the Windows.Devices.Power.Battery class.
Something to the effect of
Battery.ReportUpdated += BatteryChargeLevelChanged;
public void BatteryChargeLevelChanged(object sender, EventArgs e)
{
// show your message if the charge is low
}
Related
I have a second form that pops up upon clicking a button, a user can input some parameters for a method, save the input within a variable, and then I parse the result to an int ( thus so I can utilize it within my method ). Now, upon parsing it, the value appears to be NULL as oppose to what the user inputted within the textboxes.
var displayproperties = new int[3];
using (Form2 form = new Form2())
{
try
{
if (form.ShowDialog() == System.Windows.Forms.DialogResult.OK)
{
int i = 0;
while (i == 0)
{
if (form.click) // ok button is clicked
{
// parse values
displayproperties[0] = int.Parse(form.Height);
displayproperties[1] = int.Parse(form.Width);
displayproperties[2] = int.Parse(form.Framerate);
goto break_0; // break out of loop ( loop is to check when button is clicked )
}
}
}
}
As you can see here, the values that the user inputs is Height,Width and Framerate respectively. It parses it to an int, as I explained, and stores it in the displayproperties int array.
This is the second form:
public string Height { get; set; }
public string Width { get; set; }
public string Framerate { get; set; }
public bool click = false;
public Form2()
{
InitializeComponent();
}
private void Form3_Load(object sender, EventArgs e){}
private void textBox1_TextChanged(object sender, EventArgs e)
{
Height = height.Text;
}
private void textBox2_TextChanged(object sender, EventArgs e)
{
Width = width.Text;
}
private void textBox3_TextChanged(object sender, EventArgs e)
{
Framerate = framerate.Text;
}
public void OK_Click(object sender, EventArgs e)
{
click = true;
}
Ultimately, the values are then passed into this class:
public Class1(int width, int height)
However I get an out of range exception saying the value must be greater than zero. Goes without saying, the values I inputted were certainly greater than zero ( 800, 600, 60 respectively ) where 60 is used elsewhere.
Since my comment suggestion worked for you, I'll add it as an answer.
From what you've said, it sounds likely that you're not setting DialogResult anywhere, so your if statement is never being entered because the condition isn't met.
You should set the dialog result and close the form in OK_Click:
public void OK_Click(object sender, EventArgs e)
{
this.DialogResult = DialogResult.OK;
this.Close();
}
And then you should remove the extra code from your main form:
var displayproperties = new int[3];
using (Form2 form = new Form2())
{
try
{
if (form.ShowDialog() == System.Windows.Forms.DialogResult.OK)
{
// parse values
displayproperties[0] = int.Parse(form.Height);
displayproperties[1] = int.Parse(form.Width);
displayproperties[2] = int.Parse(form.Framerate);
}
}
}
The dialog result will serve as your click property so this is no longer required. By the way, I recommend switching to TryParse instead so that you can actively check if the input values are valid integers, as opposed to leaving it until exceptions are thrown.
An example of this:
string a = "hello"; // substitute user input here
int result;
if (!int.TryParse(a, out result))
{
MessageBox.Show($"{a} isn't a number!");
return;
}
MessageBox.Show($"Your integer is {result}");
If you're newish to programming, I recommend getting familiar with how to use the debugger. Setting a breakpoint and inspecting values as you stepped through the code would have revealed where the problem was very quickly. Microsoft have a tutorial for this.
I'm unsure of what's wrong with this code. The timer1 interval is set to 1000.
namespace timerbug
{
public partial class Form1 : Form
{
int value;
public Form1()
{
InitializeComponent();
}
private void timer1_Tick(object sender, EventArgs e)
{
do
{
value++;
label1.Text = value.ToString();
}
while (value <= 5);
}
private void button1_Click(object sender, EventArgs e)
{
value = 0;
timer1.Start();
}
}
}
I thought the label would display 1 to 5, then stop. The counting doesn't even show up until 6, and continues to go up until I stop the program. Can someone explain why the numbers 1 to 5 are not showing up, and then why it doesn't stop at 5? Thank you.
As other people have correctly pointed out in comments, it stops at 6 instead of 5 because 6 is the first value for which value <= 5 evaluates as false (You are using a do-while loop, which means the condition is evaluated after the body is executed.). In order to stop at 5, you could either use regular while loop or change the condition to value < 5 or value <= 4.
Furthermore, 6 iterations of a loop in C# happen in a few microseconds. You could not really see the numbers being displayed in the label even if everything else was done correctly, simply because it would happen too fast. In order to see anything happen, you would need to introduce some kind of a delay (Thread.Sleep()) and at the end of each iteration, you would have to call Application.DoEvents() to let the Form re-paint.
Alternatively, you could use the Timer's ticks, which would be preferable in most cases. You could do it like this for instance.
namespace timerbug
{
public partial class Form1 : Form
{
int value;
public Form1()
{
InitializeComponent();
}
private void timer1_Tick(object sender, EventArgs e)
{
if (value < 5)
{
value++;
label1.Text = value.ToString();
}
else
{
timer1.Stop();
}
}
private void button1_Click(object sender, EventArgs e)
{
value = 0;
timer1.Start();
}
}
}
Changing the timer1_tick code to this worked fine, thanks for the assistance. I have a lot to learn.
value++;
if (value >= 5)
{
timer1.Stop();
}
label1.Text = value.ToString();
label1.Invalidate();
label1.Update();
}
The premise is really simple - I have a class that is running some expensive computation and I would like to show a ProgressBar to inform the user. Since I might have many computation cycles, I want to have a simple ProgressBar form that I can use many times in my code. That form does not need to know anything else but it's title, the maximum value for the ProgressBar and when to perform a step and increment. The update call is done from the Other Class, the form just displays that.
The following code is from a Windows Forms version of a ProgressBar (exported as a dll) that achieves the goal. I am trying to recreate the same functionality with WPF. From my research so far, this cannot be done. I would love if someone can prove me wrong and demonstrate a pseudo code for both the WPF codebehind and the implentation in the Other Class.
Windows Form
public partial class ProgressForm : Form {
private bool abortFlag;
string _format;
/// <summary>
/// Set up progress bar form and immediately display it modelessly.
/// </summary>
/// <param name="caption">Form caption</param>
/// <param name="format">Progress message string</param>
/// <param name="max">Number of elements to process</param>
public ProgressForm( string caption, string format, int max )
{
_format = format;
InitializeComponent();
Text = caption;
label1.Text = (null == format) ? caption : string.Format( format, 0 );
progressBar1.Minimum = 0;
progressBar1.Maximum = max;
progressBar1.Value = 0;
Show();
Application.DoEvents();
}
public void Increment()
{
++progressBar1.Value;
if( null != _format )
{
label1.Text = string.Format( _format, progressBar1.Value );
}
Application.DoEvents();
}
public bool getAbortFlag()
{
return abortFlag;
}
private void button1_Click(object sender, EventArgs e)
{
button1.Text = "Aborting...";
abortFlag = true;
}
protected override bool ProcessDialogKey(Keys keyData)
{
if (Form.ModifierKeys == Keys.None && keyData == Keys.Escape)
{
button1.Text = "Aborting...";
abortFlag = true;
return true;
}
return base.ProcessDialogKey(keyData);
}
public void SetText(string text)
{
label1.Text = text;
System.Windows.Forms.Application.DoEvents();
}
public void SetProgressBarMinMax(int min, int max)
{
progressBar1.Minimum = min;
progressBar1.Maximum = max;
progressBar1.Value = 0;
}
public void IncrementProgressBar()
{
progressBar1.Value++;
System.Windows.Forms.Application.DoEvents();
}
public void HideProgressBar()
{
progressBar1.Visible = false;
System.Windows.Forms.Application.DoEvents();
}
public void ShowProgressBar()
{
progressBar1.Visible = true;
System.Windows.Forms.Application.DoEvents();
}
}
Some Method in Other Class
public class OtherClass(){
int counter = 0;
int n = numberOfIterations;
string s = "{0} of " + n.ToString() + String.Format(" elements processed.", counter.ToString());
string caption = "Duplicating ..";
using (ProgressForm pf = new ProgressForm(caption, s, n)){
//Something heavy to compute
foreach (var sheet in sheetsToDuplicate)
{
if (pf.getAbortFlag())
{
return;
}
counter ++;
pf.Increment();
}
}
}
I think this should be pretty straightfoward but I cannot find a single source out there to show how this can be achieved. For me, the important points to hightlight are:
The WPF (Window) ProgressBar control does not have reference to the Other Class. (because it will be shipped as a dll and should be able to adopt any scenario)
The loop is run in the Other Class.
Thank you.
I am wanting to subtract each time I click the subtract button, right now all it does is subtract it once. I guess it always sees the needed value as 4000 which is why it doesn't subtract it more than once because each click it retrieves the initial needed value.
int needed = 4000;
private void subtractBtn_Click(object sender, EventArgs e)
{
int Subtract = Convert.ToInt32(textBox_Subtract.Text);
remaining = needed - Subtract;
textBox_Remaining.Text = remaining.ToString();
if (remaining <=0)
{
MessageBox.Show("Hey it's done");
}
}
For anyone who is as dumb as me here is the final code
private void subtractBtn_Click(object sender, EventArgs e)
{
int Subtract = Convert.ToInt32(textBox_Subtract.Text);
remaining = needed - Subtract;
needed = remaining;
textBox_Remaining.Text = remaining.ToString();
if (remaining <=0)
{
MessageBox.Show("Hey it's done");
}
}
private void subtractBtn_Click(object sender, EventArgs e)
{
int Subtract = Convert.ToInt32(textBox_Subtract.Text);
remaining = needed - Subtract;
needed = remaining;
textBox_Remaining.Text = remaining.ToString();
if (remaining <=0)
{
MessageBox.Show("Hey it's done");
}
}
I am creating a simple game application in windows forms. You can drag the information from a textbox and drop it into a Dragdrop event from one MDI application to another. This is all OK but the problem I am having is that I have multiple DragDrop events and I am trying to calculate the score for all of them.
What I have tried so far is this.
public void score(int calcScore)
{
lblScore.Text += calcScore.ToString();
}
private void square_DragDrop(object sender, DragEventArgs e)
{
if(shape.Contains("Square"))
{
int calcScore = 0;
calcScore++;
score(calcScore);
}
}
private void circle_DragDrop(object sender, DragEventArgs e)
{
if(shape.Contains("Circle"))
{
int calcScore = 0;
calcScore++;
score(calcScore);
}
}
The problem is that this will add the to score together as a string so the result will be 11 instead of 2.
If I try this:
public void score(int calcScore)
{
int totalScore =0;
totalScore = totalScore + calcScore;
lblScore.Text += totalScore.ToString();
}
The problem with this is that once I initialize the totalScore it sets the total score back to 0 so the totalScore will always be 1.
How can I get the score properly calculated like this?
1.
public void score(int calcScore)
{
lblScore.Text += calcScore.ToString();
}
This does a cocatenation of the strings. So:
"1" + "1" = "11";
Just as
"cat"+"cat" = "catcat";
2.
Initialise
int totalScore =0;
int calcScore =0;
at a class level. Every time you use your DragDrop or method score(int calcScore) you are resetting these values to zero.