Progress bar withing a foreach loop - c#

I have a method that iterates through an array of music notes and plays them one after the other. I have created a progress bar that will show the status of the foreach loop.
The problem is that the progress bar is not filling up to 100% but approximately till 85%. I have also noted that the progress bar is progressing roughly, I think that this could be because the steps are large. Any ideas on how can I optimize this progress bar, pb is my instance of the progress bar, Thanks
public void PlayAll()
{
pb.Maximum = Convert.ToInt32(CountTotalDuration()); //Total lenght of the full song.
pb.Step = Convert.ToInt32(CountTotalDuration()) / Convert.ToInt32(ListSize()); //Total lenght of each note making up the song.
foreach (MusicNote m in list)
{
m.sp.Stop();
m.sp.Play();
Thread.Sleep(m.NoteDuration*100);
pb.PerformStep();
}
}

Your issue is from rounding errors in your steps. Lets look at a simple example, say you have a CountTotalDuration() of 100 and a ListSize() of 7
because you have two integer numbers / does integer division and throws away any remainder so 100 / 7 equals 14 (instead of 14.285714 with 285714 repeating). That makes your step size 14, so after doing 7 steps your total value you have reached is 98 and you would see 98% on the toolbar.
Since CountTotalDuration() appears to be the sum of NoteDuration the way to fix this is to not use equal step sizes each step. Instead, just set the max to the total duration and increment the bar by the tote duration. This will make the bar jump in proportion to the position in the song based on note length.
public void PlayAll()
{
pb.Maximum = Convert.ToInt32(CountTotalDuration()); //Total lenght of the full song.
int currentCount = 0; //Initialize our counter to 0.
foreach (MusicNote m in list)
{
m.sp.Stop();
m.sp.Play();
Thread.Sleep(m.NoteDuration*100);
//Increment the counter proportional to the length of the note.
currentCount += m.NoteDuration;
//Set the progress bar using our calculated position.
pb.Value = currentCount;
}
}
You still are going to have big jumps when long notes play, the only way to solve that is not use Thread.Sleep(m.NoteDuration*100); and instead use multiple shorter pauses and update the bar in between those pauses. Also Thread.Sleep may not be the best way to pause the loop, but I don't know what the best alternative to use instead would be, it depends on a lot of details which you have not shared with us.
You could also have similar behavior to your old method and have the note jump by 1 for each note played and just make the bar's maximum equal to the number of notes you will play.
public void PlayAll()
{
pb.Maximum = list.Length; //Or equivalent, perhaps ListSize()?
pb.Step = 1;
foreach (MusicNote m in list)
{
m.sp.Stop();
m.sp.Play();
Thread.Sleep(m.NoteDuration*100);
pb.PerformStep();
}
}
This will give you more even jumps per note but if the song is only a few notes long those even jumps could still be very large.

it sounds strange, I didn't find the problem, but I suggest you can try as this:
public void PlayAll()
{
pb.Maximum = Convert.ToInt32(ListSize()); //Total lenght of the full song.
pb.Step = 1;
int i = 1;
foreach (MusicNote m in list)
{
m.sp.Stop();
m.sp.Play();
Thread.Sleep(m.NoteDuration * 100);
pb.Value = i++;
}
}
further more, maybe you should use multithreading to improve the user experience, because Thread.Sleep() makes the form like dead.

Related

How do I reduce integer A when integer B increments?

I am generally pretty new to C# and coding in general.
Basically, this is what I have.
public bool TimeLeft;
public void Process()
{
int B = (int)Game.LocalPlayer.Character.TravelDistanceTo(spawnPoint) * 3; // An integer based on the distance of the character to a Vector3(spawnPoint).
while (TimeLeft)
{
int A = Game.GameTime / 1000; //GameTime is time lapsed in game in milliseconds.
}
}
But this is where my brain fries. Let's assume int B is 150.
How would I go about do reduce int B by 1 every time int A increases by 1? This happens within a loop.
I declare int B outside of the loop, and A inside because it needs to update every tick. TimeLeft is set somewhere else.
You have to keep track of the value of A. When you poll A anew you store the value in another variable. Then you can compute the difference and decrease B by this difference. Pseudocode:
int A = ...
int B = ...
while(...)
{
int A_new = ...
B -= A_new - A;
}
You need to define the values outside of the loop, inside the loop should only be the processing taking place. (Like Adok has mentioned)
I'd also say that while (true) is not a good practise of a general processing loop, unless you're making sure the whole program is defined within that loop.
Some game studios have a certain "Init" function, and an "Update" function, the init will happen when the game starts up the first time, and update will always be repeated like a loop after the init has been triggered. The benefit of using Update over a personal while loop is that it won't miss out out on other looping functions like Drawing
With understanding the difference between initialising and updating, It would be easier to understand a countdown like this:
In Init:
//defining 2 values to count down, one that decreases, and one that sets the value back to default.
int A = 150;
int Amax = A;
In Update:
if (A > 0)
{
A -= 1; //decrease the value if it's not at 0
}
else
{
//trigger an activity that happens when A reaches 0
//reset the timer
A = Amax;
}

How to write in multiple positions in a console application at the same time? C#

I want lines as many as the width of the console to simultaneously write downwards one char to the height of the console. I've done most of it, but it goes from top to bottom to right etc...
If you need help picturing what I mean, think of the matrix code rain.
int w = Console.WindowWidth;
int h = Console.WindowHeight;
int i = 0;
while (i < w)
{
int j = 0;
while (j < h)
{
Thread.Sleep(1);
Console.SetCursorPosition(i, j);
Console.Write(".");
j++;
}
i++;
}
What I would do is construct a List<string> lines; that would contain the lines you want to write to the console window, where each line is as wide as the console width. Then just print the list out to the console window in reverse order, so the first line (at lines[0]) will always be the last one printed, and will always be at the bottom of the console window.
Sample Implementation -- someone mentioned this might be homework. I did not think so, but if it is, then please try your own implementation of the above idea first.
We can add new items to the list in the same loop that we use to print out its items. Before we add a line, however, we first check to see if there are already as many lines in the list as there are in the console window (Console.WindowHeight). If there are, then we just remove the line at lines[0] before we add a new one. In this way, the List<string> lines is "scrolling" along with the console window.
The scrolling speed is controlled by a Thread.Sleep, but this code could easily be added to a Timer instead, so that other work could happen in the background (like if this was intended to be a "screensaver", and you wanted to wait for user input to "wake up"). But no matter how we decide to implement the speed, I decided to create an enum with values that represent the number of milliseconds a Thread.Sleep implementation would use:
class Program
{
enum MatrixCodeSpeed
{
Fastest = 0,
Faster = 33,
Fast = 67,
Normal = 100,
Slow = 333,
Slower = 667,
Slowest = 1000
}
I would also create a helper method that creates a "random" line for you. It could take in an integer that specifies the "density", which means how many characters you'd want in the line. density represents a percentage, so if 10 is specified, then we pick a random number between 0 and 99, and if it's less than 10 then we add a random matrix character to the string (otherwise we add a space character).
Also, in order to replicate the matrix a little closer, I've also chosen 4 different characters to print, each one slightly darker than the previous. This adds to the three dimensional effect, where the faded blocks look further away than the solid ones:
private static Random rnd = new Random();
// Add whatever 'matrix' characters you want to this array. If you prefer to have one
// character chosen more often than the others, you can write code to favor a specific
// index, or just add more instances of that character to the array below:
private static char[] matrixChars = new[] { '░', '▒', '▓', '█' };
static string GetMatrixLine(int density)
{
var line = new StringBuilder();
for (int i = 0; i < Console.WindowWidth; i++)
{
// Choose a random number from 0-99 and see if it's greater than density
line.Append(rnd.Next(100) > density
? ' ' // If it is, add a space to reduce line density
: matrixChars[rnd.Next(matrixChars.Length)]); // Pick a random character
}
return line.ToString();
}
Next, we have the main method, which populates a list with random lines (using a density of 10%), then prints them out one at a time, in reverse order, in an endless loop (removing the first line if we need to):
static void Main()
{
var lines = new List<string>();
var density = 10; // (10% of each line will be a matrix character)
var speed = MatrixCodeSpeed.Normal;
// Hide the cursor - set this to 'true' again before accepting user input
Console.CursorVisible = false;
Console.ForegroundColor = ConsoleColor.DarkGreen;
while (true)
{
// Once the lines count is greater than the window height,
// remove the first item, so that the list "scrolls" also
if (lines.Count >= Console.WindowHeight)
{
lines.Remove(lines[0]);
}
// Add a new random line to the list, which will be the new topmost line.
lines.Add(GetMatrixLine(density));
Console.SetCursorPosition(0, 0);
// Print the lines out to the console in reverse order so the
// first line is always last, or on the bottom of the window
for (int i = lines.Count - 1; i >= 0; i--)
{
Console.Write(lines[i]);
}
Thread.Sleep(TimeSpan.FromMilliseconds((int)speed));
}
}
}
Here's a gif of it in action, up to the point where the screen is full (then the gif repeats, but the code version continues to scroll normally):
The task smells like an assignment, so I'm guiding you instead feeding the implementation. It is not ethical to feed you with an answer if it is a homework.
You are looking for a better fit of algorithm. The stated algorithm fill the console from top to bottom, as it iterate to fill through the Y-axis first (the nested loop) and followed by the X-axis (the outer loop).
What is needed is to iterate x-axis and y-axis alternatively so that it looks like it fills from the top left corner to the bottom right corner.
// 1 step to (0,0)
*
// 3 steps to (1,1)
**
**
// 5 steps for reaching (2,2)
***
***
***
// 7 steps for reaching (3,3)
****
****
****
// 9 steps for reaching (4,4) and 11 steps for (5,5)...
// I do think everyone could get this pattern
This draft would also be the final outcome of what it looks like.
Instead of filling them all at the same time, what you need is actually get the thread sleep after it reach the next square point.
(Computers are so fast that it probably do all its work to feed your screen within a second and the black console window is gone without any notice.)
At the time you posted the question, I'm also solving it from the very beginning. I thought of filling X and Y axis alternatively is the solution, but stopping at each time that the square expands is far more important to get the effect.
It is not a threading problem tag either at my point of view.
Let's sum up the above pattern:
Assume i and j are x and y coordinates respectively.
Each iteration takes you from (i, j) and n*2+1 steps to reach
(i+1,j+1)
Note that we are zero-based in this example.
We are about to construct the loop:
The n*2+1 step number is useful. It means you need to fill x-axis for
n times and y-axis for n times, and finally get the diagonal grid
(n+1,n+1) done.
In each inner loop, we first render the X frontier along y-axis and
then render the Y frontier along x-axis.
Let say the cycle start with the checkpoint (n,n), where n=3, and we
slept for a while, so we are in n=4 now.
To achieve this, we'd better first navigate to (n+1,0) then fill up
to (n+1,n)
Afterwards we navigate to (0,n+1) and fill to (n+1,n+1)
Then we are in m=n+1 now (sounds like a mathematical proving :(
The loop would be
//calculate how many checkpoints (n)
int checkpoints = 1080;
//n should indicate the actual turn we are instead of naming the total turns like sucks
//The main, the outermost For-loop
for (int n=0;n<checkpoints;n++)
{
// The nested step
for (int y=0;y<n;y++)
{
// Just fill in (n+1, y) grid
Console.SetCursorPosition(n+1, y);
Console.Write(".");
}
for (int x=0;x<n+1;x++)
{
// Just fill in (x, n+1) grid
Console.SetCursorPosition(x, n+1);
Console.Write(".");
}
// Upon completion of each main cycle we have a sleep, yah
Thread.Sleep(100);
}
Well, I expect the program to crash when the console size is smaller than 1080x1080.
This algorithm could only get you a square to fill, and a typical monitor with resolution 1920x1080 just fails as it is 16:9. This is intentional, if you're doing homework you need to configure it before shipping it to your teacher. (I've got no chance to do an assignment as I self learned programming :(
(The site continuously urging me to format my code, this has been half an hour and I just didn't do things wrong. So I decided to post it bit by bit to debug that. Finally I've got the job done...)
If you just want to write one line at a time you can use this:
int w = Console.WindowWidth;
int h = Console.WindowHeight;
int i = 0;
while (i < h)
{
Console.WriteLine(new string('.', w-1));
Thread.Sleep(20);
i++;
}
Just a bit of modification allow the code to simulate the matrix code rain.
int w = Console.WindowWidth;
int h = Console.WindowHeight;
int i = 0;
while (i < h)
{
int j = 0;
string s = "";
Thread.Sleep(10);
while (j < w)
{
Console.SetCursorPosition(j, i);
s += ".";
j++;
}
Console.Write(s);
i++;
}
basically what i did here is just some restructuring of the logic and putting in the proper delays at the right position. Hope it helps.

Progress bar not updating as expected

The progress bar is going to 70 just fine. It's when I go to update it when the loop starts that the bar doesn't move.
int count = finalFiles.Length; //finalFiles in an array and it varies in size.
int current = 0;
private void uploadWorker_DoWork(object sender, DoWorkEventArgs e)
{
uploadWorker.ReportProgress(20);
DoSomeWork();
uploadWorker.ReportProgress(50);
DoMoreWork();
uploadWorker.ReportProgress(70);
foreach (string file in finalFiles)
{
current++;
doProcess();
uploadWorker.ReportProgress(current / count * 30 + 70);
}
}
Again, the problem is that the progress bar is not updating once it reaches 70. It just doesn't move. The form does not lock up by the way because I'm using background worker.
Does anyone know why that is?
You have an integer current, and an integer count. Since count is bigger, when you do the division it is always 0 (integer division) until current reaches current. You should either make count a double/decimal, or cast one of the two to a double/decimal before doing the division.
I don't know what doProcess() does, but shouldn't you increment current in your foreach?
Looks like you need some parentheses somewhere e.g.
foreach (string file in finalFiles)
{
doProcess();
uploadWorker.ReportProgress( ((current / count) * 30) + 70);
}
OK I don't know that maths you need (sorry, I'm in the middle of something else here), but I would suggest you put parentheses in the calculation, since it looks to me like that could be an issue.

Showing progress value from a list of tasks through ProgressBar

My title may make my question sound confusing, but it is not.
I have a list of tasks to do and a ProgressBar. When I loop through the list of tasks, I want to display the progress through a ProgressBar:
double percentage;
for(int i = 0; i < tasks.Count; i++)
{
percentage = (double)i + 1 / (double)tasks.Count;
this.Invoke((MethodInvoker)delegate
{
progressBar1.Value = (int)Math.Round(percentage * 100);
});
// Do tasks here...
}
So if I have say, 20 tasks I want progressBar1 to have the value of 5 ((1 / 20) * 100), then when it loops through again it has the value of 10, 15 and so on. The method that I am using right now does not work properly, on the first task progressBar1 has a value of 0, then when it loops through again it has the value of 100. Is there a way of doing what I am trying to achieve?
Thanks.
for(int i = 0; i < tasks.Count; i++)
{
double percentage = (double)(i + 1) / (double)tasks.Count;
Action<double> update = p =>
{
progressBar1.Value = (int)Math.Round(p * 100);
};
this.Invoke(update, percentage);
// Do tasks here...
}
Your code should essentially work, however I'd guess your UI just isn't able to update in time (i.e. there's no context switch happening and you return control only once you're done). I don't have that much experience involving C#, multithreading and UI coding, so I might be a bit off here.
What I'd try to do here is sleeping a moment (even essentially 0 seconds should do the trick) once you start doing your tasks within the tasks thread.
A bit off-topic: I'd like to mention that you're overcomplicating it a bit. Just set the maximum value of your progress bar to the number of tasks, then increase it's value 1 by 1, which removes quite a bit of obsolete math within that loop.
Edit: Yeah, just noticed Darin's answer and he's right: You're missing brackets as well, causing your percentage calculation going wrong.
But keep in mind that doing it that way might cause your total percentage to be slightly off due to precision errors (won't matter a lot depending on number of tasks; but you might not be able to hit exactly 100%).

How to take a long string and scroll it in a 15 character text control/label?

I am trying to take the lyrics of a song and scroll it in a label, but I want the label to only show 15 characters at a time. It would be like a steady scroll to the end of the song. How would I go about doing this? I have looked everywhere but I can't seem to find anything on this.
Construct a loop that sets the .Text property of the label. Each iteration of the loop should increment by however many characters you want to scroll per iteration.
string Lyrics = "This song is just six words long";
int CurrentPosition = 0;
const int CharactersToShow = 15;
for (int i = 0; i < Lyrics.Length; i++)
{
lblOutput.Text = CharactersToShow + CurrentPosition > Lyrics.Length
? Lyrics.Substring(CurrentPosition)
: Lyrics.Substring(CurrentPosition, CharactersToShow);
CurrentPosition++;
lblOutput.Update();
Thread.Sleep(250);
}
Some notes: This is just an example. As written, it monopolizes the GUI thread because it is almost always in sleep.
Instead of a sleep delay you would probably want to use a timer which updates the label every tick.
Here is a tutorial for creating a text scrolling effect in WinForms: http://www.dotnettutorials.com/tutorials/windowsprogramming/text-scroll-effect-cs.aspx
Also, there is a WinForms marquee control on CodeProject: http://www.codeproject.com/Articles/24587/Easy-to-Use-Marquee-Control-for-Windows-Form-with
Have the form use a stopwatch which calls an update method every n milliseconds. In the update method, change the text in the label by k characters. Vary k and n to match the timing of the song.

Categories