3

我正在尝试通过制作一个简单的小游戏来了解 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

4 回答 4

1

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

做这个!

于 2012-07-24T10:53:23.660 回答
1

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

于 2012-07-24T10:10:47.033 回答
0

您是否考虑过为此使用窗口窗体,其中一个面板用于输出,一个面板用于输入?

于 2012-07-24T10:16:54.083 回答
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();
            }
        }
    }
}
于 2017-09-22T03:44:33.363 回答