Progress bar in console application - c#
I'm writing a simple c# console app that uploads files to sftp server. However, the amount of files are large. I would like to display either percentage of files uploaded or just the number of files upload already from the total number of files to be upload.
First, I get all the files and the total number of files.
string[] filePath = Directory.GetFiles(path, "*");
totalCount = filePath.Length;
Then I loop through the file and upload them one by one in foreach loop.
foreach(string file in filePath)
{
string FileName = Path.GetFileName(file);
//copy the files
oSftp.Put(LocalDirectory + "/" + FileName, _ftpDirectory + "/" + FileName);
//Console.WriteLine("Uploading file..." + FileName);
drawTextProgressBar(0, totalCount);
}
In the foreach loop I have a progress bar which I have issues with. It doesn't display properly.
private static void drawTextProgressBar(int progress, int total)
{
//draw empty progress bar
Console.CursorLeft = 0;
Console.Write("["); //start
Console.CursorLeft = 32;
Console.Write("]"); //end
Console.CursorLeft = 1;
float onechunk = 30.0f / total;
//draw filled part
int position = 1;
for (int i = 0; i < onechunk * progress; i++)
{
Console.BackgroundColor = ConsoleColor.Gray;
Console.CursorLeft = position++;
Console.Write(" ");
}
//draw unfilled part
for (int i = position; i <= 31 ; i++)
{
Console.BackgroundColor = ConsoleColor.Green;
Console.CursorLeft = position++;
Console.Write(" ");
}
//draw totals
Console.CursorLeft = 35;
Console.BackgroundColor = ConsoleColor.Black;
Console.Write(progress.ToString() + " of " + total.ToString() + " "); //blanks at the end remove any excess
}
The output is just [ ] 0 out of 1943
What am I doing wrong here?
EDIT:
I'm trying to display the progress bar while I'm loading and exporting XML files. However, it's going through a loop. After it finishes the first round it goes to the second and so on.
string[] xmlFilePath = Directory.GetFiles(xmlFullpath, "*.xml");
Console.WriteLine("Loading XML files...");
foreach (string file in xmlFilePath)
{
for (int i = 0; i < xmlFilePath.Length; i++)
{
//ExportXml(file, styleSheet);
drawTextProgressBar(i, xmlCount);
count++;
}
}
It never leaves the for loop...Any suggestions?
I was also looking for a console progress bar. I didn't find one that did what I needed, so I decided to roll my own. Click here for the source code (MIT License).
Features:
Works with redirected output
If you redirect the output of a console application (e.g., Program.exe > myfile.txt), most implementations will crash with an exception. That's because Console.CursorLeft and Console.SetCursorPosition() don't support redirected output.
Implements IProgress<double>
This allows you to use the progress bar with async operations that report a progress in the range of [0..1].
Thread-safe
Fast
The Console class is notorious for its abysmal performance. Too many calls to it, and your application slows down. This class performs only 8 calls per second, no matter how often you report a progress update.
Use it like this:
Console.Write("Performing some task... ");
using (var progress = new ProgressBar()) {
for (int i = 0; i <= 100; i++) {
progress.Report((double) i / 100);
Thread.Sleep(20);
}
}
Console.WriteLine("Done.");
I know this is an old thread, and apologies for the self promotion, however I've recently written an open source console library available on nuget Goblinfactory.Konsole with threadsafe multiple progress bar support, that might help anyone new to this page needing one that doesnt block the main thread.
It's somewhat different to the answers above as it allows you to kick off the downloads and tasks in parallel and continue with other tasks;
cheers, hope this is helpful
A
var t1 = Task.Run(()=> {
var p = new ProgressBar("downloading music",10);
... do stuff
});
var t2 = Task.Run(()=> {
var p = new ProgressBar("downloading video",10);
... do stuff
});
var t3 = Task.Run(()=> {
var p = new ProgressBar("starting server",10);
... do stuff .. calling p.Refresh(n);
});
Task.WaitAll(new [] { t1,t2,t3 }, 20000);
Console.WriteLine("all done.");
gives you this type of output
The nuget package also includes utilities for writing to a windowed section of the console with full clipping and wrapping support, plus PrintAt and various other helpful classes.
I wrote the nuget package because I constantly ended up writing lots of common console routines whenever I wrote build and ops console scripts and utilities.
If I was downloading several files, I used to slowly Console.Write to the screen on each thread, and used to try various tricks to make reading the interleaved output on the screen easier to read, e.g. different colors or numbers. I eventually wrote the windowing library so that output from different threads could simply be printed to different windows, and it cut down a ton of boilerplate code in my utility scripts.
For example, this code,
var con = new Window(200,50);
con.WriteLine("starting client server demo");
var client = new Window(1, 4, 20, 20, ConsoleColor.Gray, ConsoleColor.DarkBlue, con);
var server = new Window(25, 4, 20, 20, con);
client.WriteLine("CLIENT");
client.WriteLine("------");
server.WriteLine("SERVER");
server.WriteLine("------");
client.WriteLine("<-- PUT some long text to show wrapping");
server.WriteLine(ConsoleColor.DarkYellow, "--> PUT some long text to show wrapping");
server.WriteLine(ConsoleColor.Red, "<-- 404|Not Found|some long text to show wrapping|");
client.WriteLine(ConsoleColor.Red, "--> 404|Not Found|some long text to show wrapping|");
con.WriteLine("starting names demo");
// let's open a window with a box around it by using Window.Open
var names = Window.Open(50, 4, 40, 10, "names");
TestData.MakeNames(40).OrderByDescending(n => n).ToList()
.ForEach(n => names.WriteLine(n));
con.WriteLine("starting numbers demo");
var numbers = Window.Open(50, 15, 40, 10, "numbers",
LineThickNess.Double,ConsoleColor.White,ConsoleColor.Blue);
Enumerable.Range(1,200).ToList()
.ForEach(i => numbers.WriteLine(i.ToString())); // shows scrolling
produces this
You can also create progress bars inside a window just as easily as writing to the windows. (mix and match).
You might want to try https://www.nuget.org/packages/ShellProgressBar/
I just stumbled upon this progress bar implementation - its cross platform, really easy to use, quite configurable and does what it should right out of the box.
Just sharing because i liked it a lot.
This line is your problem:
drawTextProgressBar(0, totalCount);
You're saying the progress is zero in every iteration, this should be incremented. Maybe use a for loop instead.
for (int i = 0; i < filePath.length; i++)
{
string FileName = Path.GetFileName(filePath[i]);
//copy the files
oSftp.Put(LocalDirectory + "/" + FileName, _ftpDirectory + "/" + FileName);
//Console.WriteLine("Uploading file..." + FileName);
drawTextProgressBar(i, totalCount);
}
I quite liked the original poster's progress bar, but found that it did not display progress correctly with certain progress/total item combinations. The following, for example, does not draw correctly, leaving an extra grey block at the end of the progress bar:
drawTextProgressBar(4114, 4114)
I re-did some of the drawing code to remove the unnecessary looping which fixed the above issue and also sped things up quite a bit:
public static void drawTextProgressBar(string stepDescription, int progress, int total)
{
int totalChunks = 30;
//draw empty progress bar
Console.CursorLeft = 0;
Console.Write("["); //start
Console.CursorLeft = totalChunks + 1;
Console.Write("]"); //end
Console.CursorLeft = 1;
double pctComplete = Convert.ToDouble(progress) / total;
int numChunksComplete = Convert.ToInt16(totalChunks * pctComplete);
//draw completed chunks
Console.BackgroundColor = ConsoleColor.Green;
Console.Write("".PadRight(numChunksComplete));
//draw incomplete chunks
Console.BackgroundColor = ConsoleColor.Gray;
Console.Write("".PadRight(totalChunks - numChunksComplete));
//draw totals
Console.CursorLeft = totalChunks + 5;
Console.BackgroundColor = ConsoleColor.Black;
string output = progress.ToString() + " of " + total.ToString();
Console.Write(output.PadRight(15) + stepDescription); //pad the output so when changing from 3 to 4 digits we avoid text shifting
}
I have copy pasted your ProgressBar method. Because your error was in the loop as the accepted answer mentioned. But the ProgressBar method has some syntax errors too. Here is the working version. Slightly modified.
private static void ProgressBar(int progress, int tot)
{
//draw empty progress bar
Console.CursorLeft = 0;
Console.Write("["); //start
Console.CursorLeft = 32;
Console.Write("]"); //end
Console.CursorLeft = 1;
float onechunk = 30.0f / tot;
//draw filled part
int position = 1;
for (int i = 0; i < onechunk * progress; i++)
{
Console.BackgroundColor = ConsoleColor.Green;
Console.CursorLeft = position++;
Console.Write(" ");
}
//draw unfilled part
for (int i = position; i <= 31; i++)
{
Console.BackgroundColor = ConsoleColor.Gray;
Console.CursorLeft = position++;
Console.Write(" ");
}
//draw totals
Console.CursorLeft = 35;
Console.BackgroundColor = ConsoleColor.Black;
Console.Write(progress.ToString() + " of " + tot.ToString() + " "); //blanks at the end remove any excess
}
Please note that #Daniel-wolf has a better approach: https://stackoverflow.com/a/31193455/169714
I've created this handy class that works with System.Reactive. I hope you find it lovely enough.
public class ConsoleDisplayUpdater : IDisposable
{
private readonly IDisposable progressUpdater;
public ConsoleDisplayUpdater(IObservable<double> progress)
{
progressUpdater = progress.Subscribe(DisplayProgress);
}
public int Width { get; set; } = 50;
private void DisplayProgress(double progress)
{
if (double.IsNaN(progress))
{
return;
}
var progressBarLenght = progress * Width;
System.Console.CursorLeft = 0;
System.Console.Write("[");
var bar = new string(Enumerable.Range(1, (int) progressBarLenght).Select(_ => '=').ToArray());
System.Console.Write(bar);
var label = $#"{progress:P0}";
System.Console.CursorLeft = (Width -label.Length) / 2;
System.Console.Write(label);
System.Console.CursorLeft = Width;
System.Console.Write("]");
}
public void Dispose()
{
progressUpdater?.Dispose();
}
}
Console Progress Bar in C# (Complete Code - Just copy and paste on your IDE)
class ConsoleUtility
{
const char _block = '■';
const string _back = "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b";
const string _twirl = "-\\|/";
public static void WriteProgressBar(int percent, bool update = false)
{
if (update)
Console.Write(_back);
Console.Write("[");
var p = (int)((percent / 10f) + .5f);
for (var i = 0; i < 10; ++i)
{
if (i >= p)
Console.Write(' ');
else
Console.Write(_block);
}
Console.Write("] {0,3:##0}%", percent);
}
public static void WriteProgress(int progress, bool update = false)
{
if (update)
Console.Write("\b");
Console.Write(_twirl[progress % _twirl.Length]);
}
}
//This is how to call in your main method
static void Main(string[] args)
{
ConsoleUtility.WriteProgressBar(0);
for (var i = 0; i <= 100; ++i)
{
ConsoleUtility.WriteProgressBar(i, true);
Thread.Sleep(50);
}
Console.WriteLine();
ConsoleUtility.WriteProgress(0);
for (var i = 0; i <= 100; ++i)
{
ConsoleUtility.WriteProgress(i, true);
Thread.Sleep(50);
}
}
I just stumbled upon this thread looking for something else, and I thought I'd drop off my code that I put together that downloads a List of files using the DownloadProgressChanged. I find this super helpful so I not only see the progress, but the actual size as the file is coming through. Hope it helps someone!
public static bool DownloadFile(List<string> files, string host, string username, string password, string savePath)
{
try
{
//setup FTP client
foreach (string f in files)
{
FILENAME = f.Split('\\').Last();
wc.DownloadFileCompleted += new AsyncCompletedEventHandler(Completed);
wc.DownloadProgressChanged += new DownloadProgressChangedEventHandler(ProgressChanged);
wc.DownloadFileAsync(new Uri(host + f), savePath + f);
while (wc.IsBusy)
System.Threading.Thread.Sleep(1000);
Console.Write(" COMPLETED!");
Console.WriteLine();
}
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
return false;
}
return true;
}
private static void ProgressChanged(object obj, System.Net.DownloadProgressChangedEventArgs e)
{
Console.Write("\r --> Downloading " + FILENAME +": " + string.Format("{0:n0}", e.BytesReceived / 1000) + " kb");
}
private static void Completed(object obj, AsyncCompletedEventArgs e)
{
}
Here's an example of the output:
Hope it helps someone!
I am still a little new to C# but I believe the below might help.
string[] xmlFilePath = Directory.GetFiles(xmlFullpath, "*.xml");
Console.WriteLine("Loading XML files...");
int count = 0;
foreach (string file in xmlFilePath)
{
//ExportXml(file, styleSheet);
drawTextProgressBar(count, xmlCount);
count++;
}
Based on all posts above, I did an improved version.
No jumping cursors. It's invisible now.
Improved performance (costs 1/5~1/10 time of the origin one).
Interface based. Easy to move to something else.
public class ConsoleProgressBar : IProgressBar
{
private const ConsoleColor ForeColor = ConsoleColor.Green;
private const ConsoleColor BkColor = ConsoleColor.Gray;
private const int DefaultWidthOfBar = 32;
private const int TextMarginLeft = 3;
private readonly int _total;
private readonly int _widthOfBar;
public ConsoleProgressBar(int total, int widthOfBar = DefaultWidthOfBar)
{
_total = total;
_widthOfBar = widthOfBar;
}
private bool _intited;
public void Init()
{
_lastPosition = 0;
//Draw empty progress bar
Console.CursorVisible = false;
Console.CursorLeft = 0;
Console.Write("["); //start
Console.CursorLeft = _widthOfBar;
Console.Write("]"); //end
Console.CursorLeft = 1;
//Draw background bar
for (var position = 1; position < _widthOfBar; position++) //Skip the first position which is "[".
{
Console.BackgroundColor = BkColor;
Console.CursorLeft = position;
Console.Write(" ");
}
}
public void ShowProgress(int currentCount)
{
if (!_intited)
{
Init();
_intited = true;
}
DrawTextProgressBar(currentCount);
}
private int _lastPosition;
public void DrawTextProgressBar(int currentCount)
{
//Draw current chunk.
var position = currentCount * _widthOfBar / _total;
if (position != _lastPosition)
{
_lastPosition = position;
Console.BackgroundColor = ForeColor;
Console.CursorLeft = position >= _widthOfBar ? _widthOfBar - 1 : position;
Console.Write(" ");
}
//Draw totals
Console.CursorLeft = _widthOfBar + TextMarginLeft;
Console.BackgroundColor = ConsoleColor.Black;
Console.Write(currentCount + " of " + _total + " "); //blanks at the end remove any excess
}
}
public interface IProgressBar
{
public void ShowProgress(int currentCount);
}
And some test code:
var total = 100;
IProgressBar progressBar = new ConsoleProgressBar(total);
for (var i = 0; i <= total; i++)
{
progressBar.ShowProgress(i);
Thread.Sleep(50);
}
Thread.Sleep(500);
Console.Clear();
total = 9999;
progressBar = new ConsoleProgressBar(total);
for (var i = 0; i <= total; i++)
{
progressBar.ShowProgress(i);
}
Related
using methods for program?
So I did this hangman game, and it works perfectly fine, the only problem is that I want to use methods to organize everything. And yes, it is a school project. I tried my best but whenever I try to put a part of the program in a method it's as if I removed a variable and it underlines it in red. I removed them for now so it's more clear. also, the file I used contained 19 8 letters max words, one on each line. Can someone tell me how I can incorporate methods without ruining the whole thing? also English isn't my first language plz excuse any mistakes, the code was in french and I translated it for this question. thank you very much. I appreciate your time and effort :) using System; using System.IO; namespace TP3 { class Program { public const String Dico = "dico.txt"; public static void Welcome() { //Mot de bienvenue Console.WriteLine("Welcome to hangman !"); } public static void Goodbye() { Console.WriteLine("thx for playing, goodbye!"); } public static void Program() { int SolvedWords= 0; string WordToGuess= ""; int NumberOfLetters ; int x = 0; int WordTried = 0; Console.WriteLine(""); Console.WriteLine("Do you wanna guess a word ? oui or non."); Console.WriteLine("you have 8 chances per word."); string Answer= Console.ReadLine(); Answer= Answer.ToLower(); while (Answer== "oui" && WordTried <19) { const int Lives= 8; int LostLives= 0; int LivesLeft= 8; int LettersGuesed= 0; x += 1; WordTried += 1; if (WordTried <= 20 && WordTried >1) { Console.WriteLine("Do you wanna guess a word ? oui or non."); Answer= Console.ReadLine(); Answer= Answer.ToLower(); } //Read a word in the file int compteur = 0; string ligne; // Read file and show on the line System.IO.StreamReader file = new System.IO.StreamReader(#"dico.txt"); while ((line = file.ReadLine()) != null) { compteur++; if (compteur == x) { WordToGuess= line; } } file.Close(); char[] table; table = new char[WordToGuess.Length]; for (int i = 0; i < table.Length; i++) { table[i] = WordToGuess [i]; } //change each letter into a * Console.WriteLine("here’s the word to guess : "); string HiddenWord = "********"; char[] table2; table2 = new char[WordToGuess.Length]; for (int i = 0; i < table2.Length; i++) { table2[i] = HiddenWord[i]; } for (int i = 0; i < table2.Length; i++) { Console.Write(table2[i]); } Console.WriteLine(""); //guess the word while (LettersGuesed< WordToGuess.Length && LivesLeft> 0) { Console.WriteLine(""); /* Console.WriteLine("Devinez une seule Letterdu mot. Ne pas écrire une Letter plus d'une fois de suite. Si c'est le cas, recommencez le jeu.");*/ string Letter= Console.ReadLine(); Letter= Letter.ToLower(); NumberOfLetters = Letter.Length; char[] table3; table3= new char[NumberOfLetters ]; for (int i = 0; i < table2.Length; i++) { if (table[i].Equals(Letter[0])) { Table2[i] = Letter[0]; LettersGuesed+= 1; } } for (int i = 0; i < table2.Length; i++) { Console.Write(table2[i]); } if (WordToGuess.IndexOf(Lettre) < 0) { Console.WriteLine(""); Console.WriteLine("wrong letter."); LostLives+= 1; LivesLeft= Lives- LostLives; Console.WriteLine("you have " + LivesLeft+ " lives left."); } if (WordToGuess.IndexOf(Lettre) >= 0) { Console.WriteLine(" "); Console.WriteLine("right !"); Console.WriteLine("you have " + LivesLeft+ " lives left."); } if (LettersGuesed== WordToGuess.Length && LivesLeft> 0) { SolvedWords+= 1; Console.WriteLine(" "); Console.WriteLine("you found the word !"); Console.WriteLine("you found " + SolvedWords+ " on" + WordTried + " words so far."); } if (LivesLeft== 0) { Console.WriteLine("you couldnt guess the word."); Console.WriteLine("the word was :"); for (int i = 0; i < table.Length; i++) { Console.Write(table[i]); } Console.WriteLine(" "); Console.WriteLine("you found " + SolvedWords+ " on" + WordTried + " words so far."); } if (WordTried == 19) { Console.WriteLine("no more words to guess."); } } } } static void Main(string[] args) { Welcome(); Programme(); Goodbye(); } } }
Im not going to make every method for your project, I'll help kickstart on how to think about it. Look at your current code for reading the file of words. You can move that into a method - public string[] ReadWordsFromFile() { string file = "path to your file here"; return File.ReadAllLines(file); } Or pass the file path as parameter - public string[] ReadWordsFromFile(string filePath) { return File.ReadAllLines(filePath); } Next you can have a method to get random words - public string GetRandomWord(string[] wordsArray) { Random random = new Random(); int randomIndex = random.Next(0, wordsArray.Length); return wordsArray[randomIndex]; } Note - words can be repeated if you do it this way, if you don't want that - then add logic to remove that item from the list once its used in the game. If you remove it within this method, its not actually going to remove it from the game, as you'll still be passing the entire array when getting a new word. Ill leave the implementation of that logic to you, if you want it. In the "game controller" code - you can use the above methods like this - string file = "your path to txt file"; string[] allWords = ReadWordsFromFile(file); string WordToGuess = GetRandomWord(allWords); May be your next goal should be something like this - public void GameControler() { // get all words here and other logic before game starts while (Attempts > 0) { string WordToGuess = GetRandomWord(wordsArray); // get letterGuessed from user bool letterExists = CheckIfLetterExists(WordToGuess, letterGuessed); if (!letterExists) { Attempts--; ExecuteWrongGuessMethod(x, y); } else { ExecuteRightGuessMethod(w); } } } public bool CheckIfLetterExists(string word, string letter) { if (word.Contains(letter)) return true; else return false; } public void ExecuteWrongGuessMethod(string passWhatYouNeedTo, int somethingElse) { // what to do when the guess is wrong e.g. Console.Writeline("wrong guess"); } public void ExecuteRightGuessMethod(string word) { // logic when guess is right. e.g. Show the letter guessed within the word on the console etc. } All of this isn't the best way to do it. BUT I personally feel this is logically next step a beginner takes after what you've implemented. Seeing a fully well-developed program might be too much without understanding atleast some basic concepts of OOP. After learning how to create Methods and use them, then comes classes and objects. Which should be implemented in this game, but this is all for now. I recommend you do a short C# course on coursera etc or even youtube. And slowly move towards a better understanding of SOLID principles. And by SOLID I mean an acronym for the 5 principles and not the actual word. All the best.
How to make an efficient Console Updater
Currently i wanna display the following variable Total Item Total Execution Finish Status using System; namespace ConsoleTest { class Program { static void Main(string[] args) { int TotalValue = 250; // Total Item Example int TotalExecution = 0; bool Finish_Status = false; for (int i = 0; i < TotalValue; ++i) { //Do Work Here System.Threading.Thread.Sleep(10); // Example Work TotalExecution++; if (TotalValue - TotalExecution == 0) { Finish_Status = true; } Console.Clear(); Console.Write("Progression Info\n Total Item : {0}\n Execution Total : {1}\n Remaining : {2}\n Finish_Status : {3}", TotalValue,TotalExecution, TotalValue - TotalExecution, Finish_Status); // Display Information To Console } Console.ReadLine(); } } } The result is good,however i was wondering if theres a much more efficient way of doing this,preferably updating it without using Console.Clear();
You can use Console.SetCursorPosition to move the cursor around the console buffer for each write, rather than clearing the console each time. For example: using System; namespace ConsoleTest { class Program { static void Main(string[] args) { int TotalValue = 250; // Total Item Example int TotalExecution = 0; bool Finish_Status = false; Console.Write("Progression Info\n Total Item : \n Execution Total : \n Remaining : \n Finish_Status : "); for (int i = 0; i < TotalValue; ++i) { //Do Work Here System.Threading.Thread.Sleep(10); // Example Work TotalExecution++; if (TotalValue - TotalExecution == 0) { Finish_Status = true; } Console.SetCursorPosition(26, 1); Console.Write(TotalValue); Console.SetCursorPosition(31, 2); Console.Write(TotalExecution); Console.SetCursorPosition(25, 3); Console.Write(TotalValue - TotalExecution); Console.SetCursorPosition(29, 4); Console.Write(Finish_Status); } Console.ReadLine(); } } } Disclaimer: Obviously the above is quick 'n' dirty, and would benefit from substantial refinement, but you get the idea.
Welcome kepanin_lee I think you are looking for something like this. //Console.Clear() Console.Write(vbCr & "Progression Info\n... Just start with vbCr, by this way you force to start on the beginning of the same line, so you only overwrite the last line, without clear all the screen.
Updating a clock whilst being able to input c# console [duplicate]
This question already has answers here: Writing string at the same position using Console.Write in C# 2.0 (2 answers) How can I get the position of the cursor in a console app? (2 answers) Closed 5 years ago. I'm trying to create a console application that gives me an updating clock in the corner with the ability to give an input. I've tried using multiple threads but it gives me weird errors. My clock function: public class Work { public void Count() { for (int i = 0; i < 100; i++) { DateTime date = DateTime.Now; Console.SetCursorPosition(0, 1); Console.Write(new string(' ', Console.WindowWidth)); Console.SetCursorPosition((Console.WindowWidth - 8) / 2, 0); Console.Write(String.Format("{0:HH:mm:ss}", date)); Console.WriteLine(); if (i == 90) { i = 0; } else { // Continue } } } } My main function: class Program { public static void Main(string[] args) { Console.CursorVisible = false; Work w = new Work(); Console.WriteLine("Main Thread Start"); ThreadStart s = w.Count; Thread thread1 = new Thread(s); thread1.Start(); int i = 2; Console.SetCursorPosition(0, i); i = i + 1; Console.WriteLine("Input:"); string input = Console.ReadLine(); Console.WriteLine(input); } } Does anybody know how I can achieve this, is there any possible way that I can write to a clock with a different cursor or something along the lines of that?
Try change your code like this class Program { static void Main(string[] args) { Console.CursorVisible = false; var w = new Work(); Console.WriteLine("Main Thread Start"); ThreadStart s = w.Count; var thread1 = new Thread(s); thread1.Start(); int i = 2; Console.SetCursorPosition(0, i); var format = "Input:"; Console.WriteLine(format); Console.SetCursorPosition(format.Length + 1, i); string input = Console.ReadLine(); Console.WriteLine(input); } } public class Work { public void Count() { while (true) { Thread.Sleep(1000); var originalX = Console.CursorLeft; var originalY = Console.CursorTop; Console.SetCursorPosition(0, 1); Console.Write(new string(' ', Console.WindowWidth)); Console.SetCursorPosition((Console.WindowWidth - 8) / 2, 0); Console.Write("{0:HH:mm:ss}", DateTime.Now); Console.SetCursorPosition(originalX, originalY); } } } The main idea is to store original cursor position before drawing your clock and then renurn it back. var originalX = Console.CursorLeft; var originalY = Console.CursorTop; Console.SetCursorPosition(originalX, originalY);
Auto-Updating in Console Application
I have a console Application that Asks The user to answer question, The score is display at the upper-right of the screen, I want the score to be auto-Updates when a user gives a correct answer. public void L1Timer() { Console.Clear(); int ch = 0, score = 0; Console.Write("Chances : " + ch); Console.CursorLeft = 40; Console.Write("Marks : " + score); for (int time = 0; time <= 100000; time++) { Console.SetCursorPosition(65, 0); Console.Write("Time Elapsed : " + time + " Secs"); Console.CursorLeft = 40; Thread.Sleep(1000); } } public void Level1() { Console.WriteLine("\n\n"); Console.CursorLeft = 40; Console.WriteLine("C _ _ E _ _ _ T _ _ N"); Console.WriteLine("\n\n"); int tot = 0; while (tot != 70) { Console.Write("Guess : "); string gues = Console.ReadLine(); if ((gues == "E") || (gues == "L") || (gues == "B") || (gues == "R")) { tot += 10; } } } static void Main(string[] args) { VocEnhancer VE = new VocEnhancer(); Thread T1 = new Thread(new ThreadStart (VE.L1Timer)); Console.WriteLine("\n\n\n\n\n"); Thread T2 = new Thread(new ThreadStart(VE.Level1)); T1.Start(); T2.Start(); } This is my Code...I don't know what to add to auto-update the scores.
Without your code, we can only assume and my suggestion as follows: string question = "CEO of Microsoft"; string actualAnswer ="STEVE BALLMER"; Console.WriteLine(question); string userAnswer = ""; Console.WriteLine(userAnswer); int score = 0; if(actualAnswer.Trim() == userAnswer.ToUpper().Trim()) { score++; }
First a warning: console is not meant to display graphics, menus, or to be drawn on. It is meant to be written upon, one line at the time. For all things graphics there are windows, and windows should be used, not consoles. However, if you are just playing around and making fun at your leisure time then go ahead and write characters at strange places in the console. To move the cursor use SetCursorPosition method. To find out where the cursor currently is use CursorLeft and CursorTop properties. When you want to write something at fixed coordinates save current cursor position, change to fixed position, write the text, and change back to old position. But what should happen when all text reaches the end of the screen, and text at the top disappears? Well, there are ways to solve this, but don't bother. Just use window instead of console.
Console animations
I just want to know how to create simple animations like blinking, moving stuffs on C# console applications. Is there any special method for this?
Traditional Console Spinner: static void Main(string[] args) { ConsoleSpiner spin = new ConsoleSpiner(); Console.Write("Working...."); while (true) { spin.Turn(); } } public class ConsoleSpiner { int counter; public ConsoleSpiner() { counter = 0; } public void Turn() { counter++; switch (counter % 4) { case 0: Console.Write("/"); break; case 1: Console.Write("-"); break; case 2: Console.Write("\\"); break; case 3: Console.Write("|"); break; } Console.SetCursorPosition(Console.CursorLeft - 1, Console.CursorTop); } }
Here is my spinner. The purpose of it is to have a program do some work while the spinner displays to the user that something is actually happening: public class Spinner : IDisposable { private const string Sequence = #"/-\|"; private int counter = 0; private readonly int left; private readonly int top; private readonly int delay; private bool active; private readonly Thread thread; public Spinner(int left, int top, int delay = 100) { this.left = left; this.top = top; this.delay = delay; thread = new Thread(Spin); } public void Start() { active = true; if (!thread.IsAlive) thread.Start(); } public void Stop() { active = false; Draw(' '); } private void Spin() { while (active) { Turn(); Thread.Sleep(delay); } } private void Draw(char c) { Console.SetCursorPosition(left, top); Console.ForegroundColor = ConsoleColor.Green; Console.Write(c); } private void Turn() { Draw(Sequence[++counter % Sequence.Length]); } public void Dispose() { Stop(); } } And you use the class like this: using (var spinner = new Spinner(10, 10)) { spinner.Start(); // Do your work here instead of sleeping... Thread.Sleep(10000); }
Yes, there are quite a few methods for this. In particular, you may want to look at the following Console methods: SetCursorPosition (you can move the cursor around, and overwrite elements) MoveBufferArea (copy/paste over the top of regions) ForegroundColor and BackgroundColor (change coloring)
Great work with the ConsoleSpinner and the sequence implementation. Thanks for the code. I thought about sharing my customized approach. public class ConsoleSpinner { static string[,] sequence = null; public int Delay { get; set; } = 200; int totalSequences = 0; int counter; public ConsoleSpinner() { counter = 0; sequence = new string[,] { { "/", "-", "\\", "|" }, { ".", "o", "0", "o" }, { "+", "x","+","x" }, { "V", "<", "^", ">" }, { ". ", ".. ", "... ", "...." }, { "=> ", "==> ", "===> ", "====>" }, // ADD YOUR OWN CREATIVE SEQUENCE HERE IF YOU LIKE }; totalSequences = sequence.GetLength(0); } /// <summary> /// /// </summary> /// <param name="sequenceCode"> 0 | 1 | 2 |3 | 4 | 5 </param> public void Turn(string displayMsg = "", int sequenceCode = 0) { counter++; Thread.Sleep(Delay); sequenceCode = sequenceCode > totalSequences - 1 ? 0 : sequenceCode; int counterValue = counter % 4; string fullMessage = displayMsg + sequence[sequenceCode, counterValue]; int msglength = fullMessage.Length; Console.Write(fullMessage); Console.SetCursorPosition(Console.CursorLeft - msglength, Console.CursorTop); } } Implementation: ConsoleSpinner spinner = new ConsoleSpinner(); spinner.Delay = 300; while (true) { spinner.Turn(displayMsg: "Working ",sequenceCode:5); } Output:
You'll need to use Console.ForegroundColor, Console.BackgroundColor and Console.SetCursorPosition(int, int) EDIT: For inspiration, Let's Dance
Just saw this and a few other threads about it and love this kind of stuff! I took Tuukka's nice piece of code and improved it a bit so the class can easily be set to just about any spin sequence. I'll probably add some accessors and an overloaded constructor to polish it off and put it in the ol' toolbox. Fun stuff! class ConsoleSpinner { int counter; string[] sequence; public ConsoleSpinner() { counter = 0; sequence = new string[] { "/", "-", "\\", "|" }; sequence = new string[] { ".", "o", "0", "o"}; sequence = new string[] { "+", "x" }; sequence = new string[] { "V", "<", "^", ">" }; sequence = new string[] { ". ", ".. ", "... ", "...." }; } public void Turn() { counter++; if (counter >= sequence.Length) counter = 0; Console.Write(sequence[counter]); Console.SetCursorPosition(Console.CursorLeft - sequence[counter].Length, Console.CursorTop); } }
I took the anwser from #ThisGuy and modified it a bit, but I noticed, that sometimes the row is not cleared as it should. static void Main(string[] args) { Console.WriteLine("1"); var tddf = XConsole.BusyIndicator("test 0 trtg fdfdfvdgd 4343", () => { return ""; }); Console.WriteLine("2"); var tdd = XConsole.BusyIndicator("test 0 trtg fdfdfvdgd", () => { Thread.Sleep(1); return ""; }); Console.WriteLine("3"); var t = XConsole.BusyIndicator("test 1 trtg vdgd", () => { Thread.Sleep(1000); return ""; }); Console.WriteLine("4"); var xt = XConsole.BusyIndicator("test 2", () => { Thread.Sleep(2000); return ""; }); var xtx = XConsole.BusyIndicator("test 2 csds fsd fdsf ds s", () => { Thread.Sleep(2000); return ""; }); Console.WriteLine("5"); Thread.Sleep(4000); } Spinner class: public class Spinner : IDisposable { private const string Sequence1 = #"/-\|"; private const string Sequence3 = #".o0o"; private const string Sequence2 = #"<^>v"; private const string Sequence4 = #"#■."; private const string Sequence5 = #"▄▀"; private const string Sequence = #"└┘┐┌"; private string BusyMessage = ""; private int counter = 0; private readonly int delay; private bool active; private readonly Thread thread; public Spinner(int delay = 200) { this.delay = delay; thread = new Thread(Spin); } public void Start() { active = true; Console.CursorVisible = false; if (!thread.IsAlive) { thread.Start(); } } public void Start(string busyMessage) { BusyMessage = busyMessage; Start(); } public void Stop() { active = false; Console.CursorVisible = true; ClearCurrentConsoleLine(); BusyMessage = ""; } private static void ClearCurrentConsoleLine() { int currentLineCursor = Console.CursorTop; Console.SetCursorPosition(0, Console.CursorTop); Console.Write(new string(' ', Console.WindowWidth)); Console.SetCursorPosition(0, currentLineCursor); } private void Spin() { while (active) { Turn(); Thread.Sleep(delay); } } /// <summary> /// Draws the busy indicator /// </summary> /// <param name="c">if empty char, then clear screen</param> private void Draw(char c) { int left = Console.CursorLeft; int top = Console.CursorTop; Console.Write('['); Console.ForegroundColor = ConsoleColor.Green; Console.Write(c); Console.ForegroundColor = ConsoleColor.Gray; Console.Write(']'); if (!string.IsNullOrEmpty(BusyMessage)) { Console.Write(" " + BusyMessage); } //reset cursor position Console.SetCursorPosition(left, top); } private void Turn() { Draw(Sequence[++counter % Sequence.Length]); } public void Dispose() { Stop(); } } My console class: public static class XConsole { public static T BusyIndicator<T>(Func<T> action) { T result; using (var spinner = new Spinner()) { spinner.Start(); result = action(); spinner.Stop(); } return result; } public static T BusyIndicator<T>(string content, Func<T> action) { T result; using (var spinner = new Spinner()) { spinner.Start(content); result = action(); spinner.Stop(); } return result; } } Why do I see this result sometimes? 1 2 3 st 0 trtg fdfdfvdgd ] 4 [└] test 2 csds fsd fdsf ds s Looks like the Dispose didn't trigger? Or a new Task alredy started? It should look like this: 1 2 3 4 [└] test 2 csds fsd fdsf ds s UPDATE: I added ClearCurrentConsoleLine(); and changed the Draw method, this fixed the issue.
i'm not TOO sure i know exactly what you're on about. but i'll give it a shot. I think the biggest and best way to cause the "blinking" affect (or what i think the blinking affect is) is to use a carriage return. The best way to explain it to you is to show you the Foo Bar experiment. start a new project, and in your Main function, try this. Console.WriteLine("Foo/nBar"); The output will look like this Foo Bar But if you use a carriage return. Console.WriteLine("Foo/rBar"); The output will look like this Bar The reason is that Foo is written, then the carriage return takes you BACK to the start of the line, then Bar is written. All you ever see is Bar. This can be helpful for "Moving" things on one line, instead of rewriting the same things again on multiple lines. A way to do progression would be to use Console.Write(); Try this. Console.Write("Loading"); for(int i = 0; i < 10; i++) { Thread.Sleep(1000); Console.Write("."); } The output should be Loading Followed by a Fullstop every second for 10 seconds. If you combine the Carriage return with the Console.Write(); function you can write multiple things on a single line, clear the line and write something else, or indeed, the same thing just moved slightly. (This would of course need more than i have shown you, like recording where the "object" you are controlling is situated. If you would like a short example i would be happy to do one, just comment and ask me for it :) Edit: I noticed people mentioning colour, which i forgot. If you were doing animation i guess colour would be a must. ForegroundColor and BackgroundColor are where it's at. note that ForegroundColor will apply to the next characters written to the console, it will not completely recolour the Console. /Edit I hope this helps, Skintkingle ;)
I thought I'd chime in with my version of the previously listed code. Here it is: class ConsoleSpinner { bool increment = true, loop = false; int counter = 0; int delay; string[] sequence; public ConsoleSpinner(string sSequence = "dots", int iDelay = 100, bool bLoop = false) { delay = iDelay; if (sSequence == "dots") { sequence = new string[] { ". ", ".. ", "... ", "...." }; loop = true; } else if (sSequence == "slashes") sequence = new string[] { "/", "-", "\\", "|" }; else if (sSequence == "circles") sequence = new string[] { ".", "o", "0", "o" }; else if (sSequence == "crosses") sequence = new string[] { "+", "x" }; else if (sSequence == "arrows") sequence = new string[] { "V", "<", "^", ">" }; } public void Turn() { if (loop) { if (counter >= sequence.Length - 1) increment = false; if (counter <= 0) increment = true; if (increment) counter++; else if (!increment) counter--; } else { counter++; if (counter >= sequence.Length) counter = 0; } Console.Write(sequence[counter]); Console.SetCursorPosition(Console.CursorLeft - sequence[counter].Length, Console.CursorTop); System.Threading.Thread.Sleep(delay); } } Adds delay (unfortunately through Thread.Sleep() but, hey), the ability to loop the animation forwards and backwards (starts to reverse when it hits the end), and general improvements overall. Enjoy!
This would be my prefered method: public sealed class Spinner { private static Lazy<Spinner> lazy = new Lazy<Spinner>(()=> new Spinner()); public static void Reset() { lazy = new Lazy<Spinner>(()=> new Spinner()); } public static Spinner Instance { get { return lazy.Value; }} private readonly int _consoleX; private readonly int _consoleY; private readonly char[] _frames = { '|', '/', '-', '\\' }; private int _current; private Spinner() { _current = 0; _consoleX = Console.CursorLeft; _consoleY = Console.CursorTop; } public void Update() { Console.Write(_frames[_current]); Console.SetCursorPosition(_consoleX, _consoleY); if (++_current >= _frames.Length) _current = 0; } } Call Spinner.Instance.Update() to start the spinner at the current position of the console. Any consecutive call will render the next frame at the same position. Call Spinner.Reset() if you want to write more text and then add a new spinner at a new location.
This is the way i solved it, sure it could/can be shorter but, Im just not that smart yet :-) void cc() { Console.Clear(); } void cr() { Console.ReadKey(); } byte Sleeptimer = 90; void sleepy() { System.Threading.Thread.Sleep(Sleeptimer); } string[] Loading = { #"-- ", #"\ ", #"| ", #"/ ", "Loading", " complete!" }; for (byte i = 0; i <= 15; i++) { cc(); Console.ForegroundColor = ConsoleColor.Yellow; Console.WriteLine(Loading[0] + Loading[4]); sleepy(); cc(); Console.WriteLine(Loading[1] + Loading[4]); sleepy(); cc(); Console.WriteLine(Loading[2] + Loading[4]); sleepy(); cc(); Console.WriteLine(Loading[3] + Loading[4]); sleepy(); cc(); if (i == 15) { Console.ForegroundColor = ConsoleColor.Green; Console.WriteLine(Loading[4] + Loading[5]); cc(); Console.ForegroundColor = ConsoleColor.Cyan; Next(); } } /* Now i feel even more noob while reading your code. I'm a newbie in programing. Guess this way would work if i just incfement the index of each Loading down below right? Learned too much today, forgot how this exactly works, to increment or to change the index i'd lile to acces Console.WriteLine(Loading[2] + Loading[4]); sleepy(); cc(); */
This is animation with cancellationToken private static void ClearCurrentConsoleLine() { int currentLineCursor = Console.CursorTop; Console.SetCursorPosition(0, Console.CursorTop); Console.Write(new string(' ', Console.WindowWidth)); Console.SetCursorPosition(0, currentLineCursor); } public static async Task Start(CancellationToken ct) { await Task.Run(() => { Thread.Sleep(2000); Console.WriteLine(); string text = "Executing"; for (int i = 0; i <= 3; i++) { if (ct.IsCancellationRequested) { Console.SetCursorPosition(0, Console.CursorTop - 1); ClearCurrentConsoleLine(); ct.ThrowIfCancellationRequested(); } Thread.Sleep(1000); Console.SetCursorPosition(0, Console.CursorTop - 1); ClearCurrentConsoleLine(); Console.WriteLine(text); if (i == 3) { text = "Executing"; i = 0; } text += "."; } }); }```