C#允许同时控制台输入和输出

时间:2012-07-24 09:58:46

标签: c# multithreading console

我正在尝试通过制作一个简单的小游戏来学习C#线程。我遇到了一些我当然可以使用帮助的问题。

我的愿望是同时输入和输出。线程的输出将显示在屏幕的顶部,而用户的输入可以输入到屏幕的底部。我遇到的问题是,为了刷新屏幕,当我使用Console.Clear()时,它也会消除用户输入的内容!下面我附上了我正在尝试做的极其简化的版本(为了避免不必要的代码妨碍实际问题)。

请注意:虽然在这个例子中我只更新了屏幕顶部的单个字符,但是我的实际程序在屏幕的顶部和中间会有很多文字,每次打勾都会不断变化(我计划在1.5秒内使用)。

任何想法都会很棒!我仍然是C#编程的新手,并且会为你能给予的任何帮助感到激动:)我唯一关注的是设计。顶部的系统输出,最底部的用户输入前面是“>”。如果我这样做的方式是错误的,那么把它全部抛到窗外并以不同的方式进行操作是没有问题的。

编辑:我的目标是让屏幕顶部的输出文本每1.5秒更新一次(每次运行计数线程),同时允许用户在屏幕底部键入。但是,我正在使用的方法(清除然后将新内容写入屏幕)也消除了用户的输入!它使得每1.5秒无论用户输入什么输入都消失了,这是正确的,因为这正是Console.Clear所做的。所以我正在寻找一种新方法来完成这项任务。

简而言之:如何更新屏幕顶部/中间的文字,同时允许用户继续在屏幕底部输入内容?

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;

namespace ConsoleApplication2
{
    class Program
    {

        static int i = 0;

        static void Main(string[] args)
        {
            Thread tickThread = new Thread(new ThreadStart(CountThread));
            Thread userThread = new Thread(new ThreadStart(UserInput));
            tickThread.Start();
            Thread.Sleep(1);
            userThread.Start();
            Thread.Sleep(20000);
            tickThread.Abort();
            userThread.Abort();
        }

        static void UserInput()
        {
            string input = "";
            while (true)
            {
                input = Console.ReadLine();
            }
        }


        static void CountThread()
        {
            while (true)
            {
                Console.Clear();
                Console.SetCursorPosition(0, 0);
                Console.WriteLine(i);
                i++;
                Console.SetCursorPosition(0, Console.WindowHeight - 1);
                Console.Write("> ");
                Thread.Sleep(1500);

            }
        }

    }
}

4 个答案:

答案 0 :(得分:1)

您可以在控制台中的每个单元格的循环中设置cursor position,除了为用户输入设计的单元格,并写入空格符号。从本质上讲,这将清除控制台窗口的一部分。 此外,您可以使用相同的方法将输出部分呈现到控制台。

答案 1 :(得分:1)

您可以使用Console.ReadKey通过字符读取输入字符。如果存储输入,则可以重建整个屏幕,包括在清除控制台之前键入的输入。我建议在一个单独的线程中做所有I / O相关。您可以保留由多个线程更新的控制台的内部表示,然后从一个线程打印它。

这样做!

答案 2 :(得分:0)

您是否考虑使用窗口表单,其中有一个输出面板和一个输入面板?

答案 3 :(得分:0)

这是一种方法,它具有主线程读取控制台输入,以及第二个线程来编写控制台输出:

using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;

namespace ConsoleReadWriteTest
{
    class Program
    {
        private static ConsoleInfo consoleInfo = new ConsoleInfo();
        static void Main(string[] args)
        {
            Thread consoleWriter = new Thread(new ThreadStart(ConsoleWriter));
            consoleWriter.Start();

            consoleInfo.outputBuffer.Add("Running.");
            consoleInfo.outputBuffer.Add(".. status of foo = good");
            consoleInfo.outputBuffer.Add(".. status of bar = bad");

            while (true)
            {
                var key = Console.ReadKey(true);
                lock (consoleInfo)
                {
                    if (key.Key == ConsoleKey.Enter)
                    {
                        consoleInfo.commandReaty = true;
                    }
                    else
                    {
                        consoleInfo.sbRead.Append(key.KeyChar.ToString());
                    }
                }
            }

        }

        static void ConsoleWriter()
        {
            while (true)
            {
                lock(consoleInfo)
                {
                    Console.Clear();

                    if (consoleInfo.outputBuffer[0].Length > 20)
                    {
                        consoleInfo.outputBuffer[0] = "Running.";
                    }
                    else
                    {
                        consoleInfo.outputBuffer[0] += ".";
                    }

                    foreach (var item in consoleInfo.outputBuffer)
                    {
                        Console.WriteLine(item);
                    }

                    Console.WriteLine("--------------------------------------------------------------");

                    if (consoleInfo.commandReaty)
                    {
                        consoleInfo.commandReaty = false;
                        consoleInfo.lastCommand = consoleInfo.sbRead.ToString();
                        consoleInfo.sbRead.Clear();
                        consoleInfo.lastResult.Clear();
                        switch (consoleInfo.lastCommand)
                        {
                            case "command1":
                                consoleInfo.outputBuffer[2] = ".. status of bar = good";
                                consoleInfo.lastResult.Append("command #1 performed");

                                break;
                            case "command2":
                                consoleInfo.outputBuffer[2] = ".. status of bar = bad";
                                consoleInfo.lastResult.Append("command #2 performed");
                                break;
                            case "?":
                                consoleInfo.lastResult.AppendLine("Available commands are:");
                                consoleInfo.lastResult.AppendLine("command1     sets bar to good");
                                consoleInfo.lastResult.AppendLine("command1     sets bar to bad");
                                break;
                            default:
                                consoleInfo.lastResult.Append("invalid command, type ? to see command list");
                                break;
                        }
                    }

                    Console.WriteLine(consoleInfo.lastCommand);
                    Console.WriteLine(consoleInfo.lastResult);
                    Console.WriteLine();
                    Console.Write(">");
                    Console.WriteLine(consoleInfo.sbRead.ToString());
                    Console.WriteLine();
                    Console.WriteLine();
                    Console.WriteLine();
                }

                Thread.Sleep(250);
            }
        }
        private class ConsoleInfo
        {
            public bool commandReaty { get; set; }
            public StringBuilder sbRead { get; set; }
            public List<string> outputBuffer { get; set; }
            public string lastCommand { get; set; }
            public StringBuilder lastResult { get; set; }

            public ConsoleInfo()
            {
                sbRead = new StringBuilder();
                outputBuffer = new List<string>();
                commandReaty = false;
                lastResult = new StringBuilder();
            }
        }
    }
}