Reputation: 13
I'm building a c# console app (.NET framework) and i want to make a nice looking app by using some "animations". I want to print "Press any Key to continue ..." and have it flashing ( appear then disappear until the user actually presses any key.
do
{
while (!Console.KeyAvailable)
{
Console.WriteLine("Press any key to continue...");
/* here i want the program to wait for like 500ms,
clear console and wait 500ms again before rewriting line*/
Console.Clear();
}
} while (Console.ReadKey(true).Key != ConsoleKey.Escape);
Upvotes: 1
Views: 26487
Reputation: 6891
I've improved on this answer, which causes high CPU usage. My answer lets the CPU rest idle during the wait but requires adding reference to System.Windows.Forms
.
private static void Timer_Tick (object sender, EventArgs e)
{
((System.Windows.Forms.Timer)sender).Stop();
}
private static ConsoleKey FlashPrompt(string prompt, TimeSpan interval)
{
// Capture the cursor position and console colors
var cursorTop = Console.CursorTop;
var colorOne = Console.ForegroundColor;
var colorTwo = Console.BackgroundColor;
// Write the initial prompt
Console.Write(prompt);
// Set up timer
System.Windows.Forms.Timer timer = new System.Windows.Forms.Timer();
timer.Tick += Timer_Tick;
timer.Interval = (int)interval.TotalMilliseconds;
while (!Console.KeyAvailable)
{
// Wait the required interval, checking every 100ms
timer.Start();
while (!Console.KeyAvailable && timer.Enabled)
{
Application.DoEvents();
System.Threading.Thread.Sleep(100);
}
// Wwap the colors, and re-write our prompt
Console.ForegroundColor = Console.ForegroundColor == colorOne
? colorTwo : colorOne;
Console.BackgroundColor = Console.BackgroundColor == colorOne
? colorTwo : colorOne;
Console.SetCursorPosition(0, cursorTop);
Console.Write(prompt);
}
// Reset colors to where they were when this method was called
Console.ForegroundColor = colorOne;
Console.BackgroundColor = colorTwo;
return Console.ReadKey(true).Key;
}
Upvotes: 0
Reputation: 37020
A slightly different approach would be to use the Stopwatch
class to measure time, and only change the text if we've passed the specified "flash interval".
We could write a method to do this, which would take in a string prompt
to display, and a TimeSpan interval
that specifies how long to wait between flashing the text.
In the code, we would capture the cursor position and console colors, start a stopwatch, and then every time the stopwatch passes the amount of time specified by interval
, we would swap the Console.ForegroundColor
and Console.BackgroundColor
.
The method would do this until the user presses a key, which we would return back to the caller:
private static ConsoleKey FlashPrompt(string prompt, TimeSpan interval)
{
// Capture the cursor position and console colors
var cursorTop = Console.CursorTop;
var colorOne = Console.ForegroundColor;
var colorTwo = Console.BackgroundColor;
// Use a stopwatch to measure time interval
var stopwach = Stopwatch.StartNew();
var lastValue = TimeSpan.Zero;
// Write the initial prompt
Console.Write(prompt);
while (!Console.KeyAvailable)
{
var currentValue = stopwach.Elapsed;
// Only update text with new color if it's time to change the color
if (currentValue - lastValue < interval) continue;
// Capture the current value, swap the colors, and re-write our prompt
lastValue = currentValue;
Console.ForegroundColor = Console.ForegroundColor == colorOne
? colorTwo : colorOne;
Console.BackgroundColor = Console.BackgroundColor == colorOne
? colorTwo : colorOne;
Console.SetCursorPosition(0, cursorTop);
Console.Write(prompt);
}
// Reset colors to where they were when this method was called
Console.ForegroundColor = colorOne;
Console.BackgroundColor = colorTwo;
return Console.ReadKey(true).Key;
}
Now, on the calling side, we would pass it the text "Press escape to continue" and the amount of time we want to wait (TimeSpan.FromMilliseconds(500)
in your case), and then we could call this in an infinite while
loop, until the user presses ConsoleKey.Escape
:
private static void Main()
{
// Flash prompt until user presses escape
while (FlashPrompt("Press escape to continue...",
TimeSpan.FromMilliseconds(500)) != ConsoleKey.Escape) ;
// Code execution continues after they press escape...
}
The nice thing here is that you can re-use the logic and can specify shorter or longer flash times. You can also change the colors that get "flashed" by specifying them before calling the method (or the method could be written to take them as arguments).
For example, try this out:
private static void Main()
{
Console.WriteLine("Hello! The text below will flash red " +
"and green once per second until you press [Enter]");
Console.ForegroundColor = ConsoleColor.Red;
Console.BackgroundColor = ConsoleColor.Green;
while (FlashPrompt("Press [Enter] to continue...",
TimeSpan.FromSeconds(1)) != ConsoleKey.Enter) ;
Console.ResetColor();
// Code will now continue in the original colors
}
Upvotes: 2
Reputation: 3235
You can perform a batch of actions with equal intervals like this:
using System;
using System.Threading;
namespace ConsoleApp
{
class Program
{
static void Main(string[] args)
{
new Program().Run();
}
private void Run()
{
do
{
while (!Console.KeyAvailable)
this.InvokeWithIntervals(1000,
() => Console.WriteLine("Press any key to continue..."),
() => Console.Clear());
} while (Console.ReadKey(true).Key != ConsoleKey.Escape);
}
private void InvokeWithIntervals(int interval, params Action[] actions)
{
foreach(var action in actions)
{
action.Invoke();
Thread.Sleep(interval);
}
}
}
}
Upvotes: 1
Reputation: 4826
First off, I would not use Thread.Sleep
for this. Sleeping your main thread provides a pretty rough user experience... It's a quick and dirty approach, but not really what that method is for.
Here's a quick example that uses a timer to flash a line of text.
using System.Timers;
class Program
{
static void Main(string[] aszArgs)
{
Timer myTimer = new Timer(500);
myTimer.Elapsed += MyTimer_Elapsed;
myTimer.Enabled = true;
//Wait for a key. Or do other work... whatever you want
Console.ReadKey();
}
private static bool cleared = true;
private static void MyTimer_Elapsed(object sender, ElapsedEventArgs e)
{
if (cleared)
Console.WriteLine("Flash text");
else
Console.Clear();
cleared = !cleared;
}
}
I use System.Timers.Timer
in this example, which has some solid documentation and examples here.
Upvotes: 2
Reputation:
A simple way to do this is to use
System.Threading.Thread.Sleep(5000); //Pauses for 5 Seconds. So to flash do this.
Console.Clear();
Console.WriteLine("SomeText");
System.Threading.Thread.Sleep(1000);
Console.Clear();
Console.WriteLine("SomeText");
System.Threading.Thread.Sleep(1000);
/// ETC..
Console.WriteLine("Press Any key To Continue...)
This is the simple way to do it and will help with your understanding of coding. If you want it to continue flashing then simply place it inside of a loop. HOWEVER! Keep in mind this effectively "Pauses" code from running. So if it is on a pause line, it WILL NOT allow a user to press a key to continue. That's why I placed the final Console.WriteLine();
at the bottom. If you want the user to be able to press a key at any time and make it flash continually then you're going to have to get involved in multi-threading, which is likely a bit more complex than what you are interested in.
Upvotes: 6