qqqqqkks
qqqqqkks

Reputation: 247

Run other code while timer is running in c#

I am making a C# console maths test where the user answers maths questions

I am trying to add a timer to the test, but I can't make my timer run at the same time as my other code

Here is an example of my code:

class Program
{
    public static OtherCode()
    {
        \\*other code for test
    }
    public class Timer
    {
        public static int Timers(int timeLeft)
        {
            do
            {
                Console.Write("\rtimeLeft: {0} ", timeLeft);
                timeLeft--;
                Thread.Sleep(1000);
            } while (timeLeft > 0);
            Console.Write(Environment.NewLine);
            return timeLeft;
        }
    }
    
    public static void Main(string[] args)
    {
        int numberOfSeconds = 30;
        Timer.Timers(numberOfSeconds);

        \\other code
        OtherCode();
    }
}

I would like my timer to be running at the top of the console and the maths questions to be asked underneath like this except the question should be on a newline: enter image description here

Any help appreciated!

UPDATE

When I add Console.SetCursorPosition() to my code like so:

do
    {
        Console.SetCursorPosition(0, 9);        
        Console.Write("\rtimeLeft: {0} ", timeLeft);
        timeLeft--;
        Thread.Sleep(1000);
    } while (timeLeft > 0);

My code won't move the timer but when I type the answer to one of my maths questions it makes me type it on the same line as the timer like this: enter image description here

Upvotes: 1

Views: 863

Answers (3)

JonC
JonC

Reputation: 978

In order to have a status message that stays at the bottom of the console you need a way to manipulate the screen buffer so you continuously overwrite your status message.

The Console.SetCursorPos can be used for this and is usefull in more advanced scenarios, but I think you can get by with simply using \r to reset the cursor to the beginning of the line.

Proof of consept:

using System;

namespace consoletimer
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Hello World!");
            int numberOfSeconds = 300;
            var thread = new System.Threading.Thread(()=> PrintStatusMessage(numberOfSeconds));
            thread.Start();
            int n = 5;
            while(n-- > 0){
                WriteToScreen("Example text", false);
                ReadInput();
                System.Threading.Thread.Sleep(2000);
            }
        }

        static void PrintStatusMessage(int numberOfSeconds){
            var whenToStop = DateTime.Now.AddSeconds(numberOfSeconds);
            while(DateTime.Now < whenToStop){
                var timeLeft = (whenToStop-DateTime.Now).ToString(@"hh\:mm\:ss");
                WriteToScreen($"Time Remaining: {timeLeft}", true);
                System.Threading.Thread.Sleep(500);
            }
        }

        static string ReadInput(){
            string input = Console.ReadLine();
            Console.Write(new string(' ',100));
            Console.CursorLeft = 0;
            return input;
        }

        static object lockObject = new object();

        static void WriteToScreen(string message, bool resetCursor){
            lock(lockObject){
                if(resetCursor){
                    int leftPos = Console.CursorLeft;
                    Console.WriteLine();
                    Console.Write(message.PadRight( 50, ' '));
                    Console.CursorTop--;
                    Console.CursorLeft = leftPos;
                }
                else{
                    Console.WriteLine(message);
                    Console.Write(new string(' ',100));
                    Console.CursorLeft = 0;
                }   
            }
        }
    }    
}

Edit

We need to clear the next line whenever we write to the console so that we remove the status message that was there previously.

Upvotes: 1

you can simply use threads this way

using System.Threading;

namespace ConsoleApp1
{
    class Program
    {
        public static void OtherCode()
        {
            Console.ReadKey();
            //other code for test
        }

        public static void Main(string[] args)
        {

            Thread thread = new Thread(new ThreadStart(Job));
            thread.Start();

            //other code
            OtherCode();
        }

        public static void Job()
        {
            int numberOfSeconds = 30;
            Timer.Timers(numberOfSeconds);
        }
    }

    class Timer
    {
        public static int Timers(int timeLeft)
        {
            do
            {
                Console.Write("\rtimeLeft: {0} ", timeLeft);
                timeLeft--;
                Thread.Sleep(1000);
            } while (timeLeft > 0);
            Console.Write(Environment.NewLine);
            return timeLeft;
        }
    }
}

or

    public static void Main(string[] args)
    {

        Thread thread = new Thread(new ThreadStart(() => {
            int numberOfSeconds = 30;
            Timer.Timers(numberOfSeconds);
        }));
        thread.Start();

        //other code
        OtherCode();
    }

Upvotes: 0

Marvin Klein
Marvin Klein

Reputation: 1746

You can start the Timers method within a second Thread.

To do so you need to use System.Threading Namespace. Take a look at: Start Parameterized Thread

Upvotes: 1

Related Questions