【问题标题】:Write to console while waiting for input在等待输入时写入控制台
【发布时间】:2022-04-18 21:53:44
【问题描述】:

我是一名编程初学者,我需要编写一个 c# 控制台应用程序,它会在循环中执行某些操作(假设将星号写入控制台),直到用户输入“停止”之类的命令。 像这样的:

While !('user entered word "stop"'){
    Console.Write("*")
}

程序应该独立于任何用户按键或其他命令来编写星号,只需在用户准确写入“停止”并按 Enter 之前执行它即可。 这个:

string userinput = "";
while (true){
     Console.Write("*");
     userinput = Console.ReadLine();
     if(userinput == "stop"){
         break;
     }
}

不是一个解决方案,因为它会在每个星号打印后不断询问用户输入。

对不起,如果这是一个愚蠢的问题,我什至不明白从哪里开始。

编辑: 好的,它可以是另一项任务,例如复制文件或播放音乐或其他任何东西。我只是不明白如何不断检查控制台 在不询问用户的情况下输入停用词。控制台可以为空,等待用户输入。

【问题讨论】:

  • 只需将while !(userinput) 替换为while (true),因为当用户键入“停止”时,您将跳出循环
  • 控制台忙于写星星时,用户如何打字?
  • "在控制台忙于写星星的时候,用户如何打字?" - 这就是我想要弄清楚的。
  • 在我看来,您需要一种在不阻止程序执行的情况下检查键盘输入的方法。或许可以查看Console.KeyAvailable 属性。
  • 如果您不想等待用户在每颗星之间按回车,那么您要查找的内容需要多个线程和多个控制台窗口。

标签: c# loops user-input


【解决方案1】:

当用户按下任意键时,这将停止

        while (!Console.KeyAvailable)
        {
            Console.Write("*");
        }

这只会在用户按下 Escape 时停止:

        while (true)
        {
            Console.Write("*");

            if (Console.KeyAvailable && Console.ReadKey().Key == ConsoleKey.Escape)
            {
                break;
            }
        }

如果您希望用户必须输入多个字母(例如“停止”),您必须阅读他们按下的所有键并检查最后四个是否为“停止”。

【讨论】:

    【解决方案2】:

    如果控制台同时用于打印星星,他将在哪里写入输入。 您可以循环打印星星,直到未按下键盘上的特定按钮。 之后,您可以制定逻辑将按下的键保存到变量中并循环,直到未写入特定组合。不要忘记将 Sleep 放在你的循环中。 无论如何,同时写星星和写输入并不是一个好主意。

    【讨论】:

      【解决方案3】:

      有一个good answer here 关于在不锁定主线程的情况下读取输入。您可以在单独的线程中使用Console.KeyAvailableConsole.ReadKey()

      同时写回控制台有点棘手。如果您让用户盲目输入(这样他们就看不到他们输入的内容),这会更容易。但是当你想向用户显示他们输入的内容时问题就开始了,因为你必须自己将用户输入写回控制台(因为你不能使用Console.ReadLine()来做到这一点你)。而且,我想,您不希望在他们的输入中间出现星星,例如:

      s*****t***o**p
      

      我假设你想要更多类似的东西:

      ***********
      stop
      

      这意味着您需要在控制台中移动光标以将星号写在一行上,并将用户输入写在另一行上。

      您应该能够使用Console.SetCursorPosition 执行此操作,以根据您要在哪一行上写字上下移动光标。但是您还必须记录到目前为止您在每行上写了多少个字符。

      【讨论】:

        【解决方案4】:

        您可以使用多线程来实现这一点。这样,主线程将启动一个后台线程,该线程将写入星号,直到人员停止输入并按下回车键。但是,它可能会影响它的显示方式,因为在您键入时,它看起来会自动将星号添加到您按下的键上,但不用担心,具体取决于您的计时器。当你按下 Enter 键时,它不会读取之前添加的星星。

        下面是一个示例代码,供您实现您想要的。

            using System;
            using System.Collections.Generic;
            using System.Linq;
            using System.Text;
            using System.Threading;
            using System.Threading.Tasks;
        
            namespace Practice
        {
            class Program
            {
                static bool write = true;
                static void Main(string[] args)
                {
                    //Write the stars using a background thread
                    new Thread(() =>
                    {
                        Thread.CurrentThread.IsBackground = true;
                        WriteStars();
                    }).Start();
        
                    while (true)
                    {
                        //Read the user input
                        var input = Console.ReadLine();
                        //Check the user input
                        if (input.Equals("stop", StringComparison.OrdinalIgnoreCase))
                        {
                            write = false;
                            Console.WriteLine("Finished. Program stopped!");
                            Console.ReadKey();
                            break;
                        }
                    }
                }
        
                private static void WriteStars()
                {
                    while (write)
                    {
                        Console.Write("*");
        
                        //Make the thread wait for half a second
                        Thread.Sleep(500);
                    }
                }
            }
        }
        

        谢谢

        【讨论】:

        • 这个“线程”的东西似乎是答案,我早上试试,提前谢谢。
        【解决方案5】:

        这是一个相当复杂的解决方案。它不是在寻找“停止”这个词,它只是提示输入一个字符串(任何字符串)。不过这很容易适应。

        它每 250 毫秒轮询一次键盘以获取按键输入。如果两秒钟没有输入,它会输出一个星号。当您输入一个字符(或退格)时,它会写出整行(在右侧用空格填充),将现有的星号删除。

        它不关心的一件事是换行。如果你让它足够长的时间使该行充满星号,那么控制台将换行到第二行,这些星号将永远不会被空白。

        我很惊讶,但这实际上感觉像是一个合理的 UI。我不确定是否值得增加复杂性,但是...

          public static string GetString(string prompt)
          {
              const int pollTime = 250;       //milliseconds
              const int starTime = 8;         //pollTime quantums (in this case 2 * 250 = 2000 ms)
              string buffer = string.Empty;
              Console.Write($"{prompt}: ");
              var top = Console.CursorTop;
              var left = Console.CursorLeft;
              //two loops, 
              //outer loop is per character
              //the inner one causes a star to be output every 2 seconds, 
              //it causes the keyboard to be polled every 1/4 second
              while (true)        //this loop breaks with a return statement
              {
                  var noChar = true;
                  var starLoopCount = 0;
                  while (noChar && starLoopCount < starTime)
                  {
                      if (Console.KeyAvailable)
                      {
                          var keyRead = Console.ReadKey();
                          if (keyRead.Key == ConsoleKey.Enter)
                          {
                              OutputLine(left, top, buffer);
                              return buffer;
                          }
        
                          if (keyRead.Key == ConsoleKey.Backspace)
                          {
                              if (buffer.Length > 0)
                              {
                                  buffer = buffer.Substring(0, buffer.Length - 1);
                                  OutputLine(left, top, buffer);
                                  noChar = false;
                                  continue;
                              }
                          }
                          //otherwise, add the key to the buffer
                          buffer += keyRead.KeyChar;
                          OutputLine(left, top, buffer);
                          noChar = false;
                          starLoopCount = 0;
                      }
                      ++starLoopCount;
                      Thread.Sleep(pollTime);
                  }
        
                  if (noChar)
                  {
                      Console.Write("*");
                  }
              }
          }
        
          private static void OutputLine(int left, int top, string line)
          {
              Console.SetCursorPosition(left, top);
              var blank = new string(' ', 80 - left - line.Length);
              Console.Write(line + blank);
              Console.SetCursorPosition(left + line.Length, top);
          }
        

        【讨论】:

          【解决方案6】:

          您可以使用 do while 循环,并请求一个值。 例如(如果str等于退出while循环将结束,循环将结束)

          string objVal;
          string str;
           do {
               Console.WriteLine("Enter a value: ");
               str = Console.ReadLine();
                if (!str.Equals("exit")){ 
                    //logic (just an example)
                     objVal = str; 
                  }
                } while (!str.Equals("exit"));
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2015-12-25
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2011-08-27
            • 1970-01-01
            • 2013-11-13
            相关资源
            最近更新 更多