C ++ - 覆盖以前输出到控制台的多行

时间:2017-11-16 23:03:22

标签: c++ mingw console-application

如果我在控制台中显示了一个字符网格,是否有任何实用的方法可以重写这些多行,以便在控制台的相同行上输出更改的网格。

例如,我想要这段代码:

#include <iostream>

using namespace std;

int main() {
        for (int i=0; i<5; i++) {
                for (int j=0; j<5; j++) {
                        cout << "-";
                }
                cout << endl;
        }

        getchar();

        for (int i=0; i<5; i++) {
                cout << '\r';
                for (int j=0; j<5; j++) {
                        cout << "x";
                }
                cout.flush();
        }

        return 0;
}

输出:

-----
-----
-----
-----
-----

然后,在用户输入时,用;

覆盖它
xxxxx
xxxxx
xxxxx
xxxxx
xxxxx

我看到人们通过输出'\ r'重新编写行来显示加载栏类型显示的其他示例,但我不确定是否有任何直接的方法来实现多个行?

我正在使用MinGW。

一个解决方案:

#include <iostream>
#include <stdio.h>
#include <windows.h>

using namespace std;

void gotoxy( int column, int line )
  {
  COORD coord;
  coord.X = column;
  coord.Y = line;
  SetConsoleCursorPosition(
    GetStdHandle( STD_OUTPUT_HANDLE ),
    coord
    );
  }

int main() {
        for (int i=0; i<5; i++) {
                for (int j=0; j<5; j++) {
                        cout << "-";
                }
                cout << endl;
        }

        getchar();

        gotoxy(0,0);

        for (int i=0; i<5; i++) {
                for (int j=0; j<5; j++) {
                        cout << "x";
                }
                cout << endl;
        }

        return 0;
}

3 个答案:

答案 0 :(得分:2)

您可以使用SetConsoleCursorPosition设置光标位置。

答案 1 :(得分:2)

您可以在两个循环之间添加此代码块以清除屏幕。

    printf("\033[2J");
    printf("\033[%d;%dH", 0, 0);

它使用ANSI转义序列来执行此操作。您还需要添加#include <stdio.h>以支持printf()

也不需要\r,您应该将cout.flush();替换为cout << endl;

你的代码最终应该是这样的:

#include <iostream>
#include <stdio.h>
using namespace std;

int main() 
{
    for (int i=0; i<5; i++) {
            for (int j=0; j<5; j++) {
                    cout << "-";
            }
            cout << endl;
    }

    getchar();
    printf("\033[2J");
    printf("\033[%d;%dH", 0, 0);

    for (int i=0; i<5; i++) {
            for (int j=0; j<5; j++) {
                    cout << "x";
            }
            cout<<endl;
    }

    return 0;
}

答案 2 :(得分:1)

  

是为多行实现这一目标的直接方法吗?

是。 Ansi终端是一种直接的便携式解决方案。我曾经使用的每台PC都有Ansi终端仿真。在ubuntu上,gnome-terminal工作正常。我一直使用ansi转义序列。

对于这项工作,您可能只需要goto和clear screen,但还有更多的ansi终端功能。

由于您已将此帖标记为C ++,请考虑以下事项。

#include <chrono>
// 'compressed' chrono access --------------vvvvvvv
typedef std::chrono::high_resolution_clock  HRClk_t; // std-chrono-hi-res-clk
typedef HRClk_t::time_point                 Time_t;  // std-chrono-hi-res-clk-time-point
typedef std::chrono::milliseconds           MS_t;    // std-chrono-milliseconds
typedef std::chrono::microseconds           US_t;    // std-chrono-microseconds
typedef std::chrono::nanoseconds            NS_t;    // std-chrono-nanoseconds
using   namespace std::chrono_literals;  // support suffixes like 100ms, 2s, 30us
#include <iostream>
#include <iomanip>
#include <thread>


class Ansi_t   // use ansi features of gnome-terminal, 
{              // or any ansi terminal
   // note: Ubuntu 15.10 gnome-terminal ansi term cursor locations 
   //       are 1-based, with origin 1,1 at top left corner

   enum ANSI : int { ESC = 27 }; // escape 

public:

   static std::string clrscr(void)
      {
         std::stringstream ss;
         ss << static_cast<char>(ESC)<< "[H"   // home
            << static_cast<char>(ESC)<< "[2J"; // clrbos
         return(ss.str());
      }

   //       r/c are 0 based------v------v------0 based from C++
   static std::string gotoRC(int r, int c)
      {
         std::stringstream ss;
         // Note: row/col of my apps are 0 based (as in C++)
         // here I fix xy to 1 based, by adding 1 while forming output
         ss << static_cast<char>(ESC)<< "[" 
            << (r+1) << ';' << (c+1) << 'H';
         return(ss.str());
      }

   // tbr - add more ansi functions when needed

}; // Ansi_t

注意:我偶尔会添加断言以强制执行r和c>> =。

用法示例:

int main(int, char**)
{    
   int retVal = -1;
   {
      Time_t start_us = HRClk_t::now();

      {
         std::cout << Ansi_t::clrscr() << std::flush;  // leaves cursor at top left of screen

         for (int i=0; i<10; ++i)
         {

            for (int r=0; r<5; ++r) // 0 based
            {
               std::cout << Ansi_t::gotoRC(r+5, 5)  // set cursor location
                         << "-----" << std::flush;
            }

            std::this_thread::sleep_for(500ms);

            // to overwrite
            for (int r=0; r<5; ++r)
            {
               std::cout << Ansi_t::gotoRC(r+5, 5)  // set cursor location
                         << "xxxxx" << std::flush;
            }

            std::this_thread::sleep_for(500ms);

            std::cout << Ansi_t::gotoRC(11,5) << 9-i << std::flush;

         }// for i


         std::cout << "\n\n" << std::endl;

         return 0;
      }

      auto  duration_us = std::chrono::duration_cast<US_t>(HRClk_t::now() - start_us);

      std::cout << "\n\n  duration  " << duration_us.count() << " us" << std::endl;
   }

   return(retVal);
}

使用这些Ansi_t方法可以直接进行记忆。来自工作代码的示例片段:

  1. 向班级
  2. 添加数据属性
    std::string     m_toRowCol;  // cursor position string
    
    1. 在ctor
    2. 中预填充字符串
       FOO_t::FOO_t( ... )
       : m_seqId     (a_gb.gBoardSz())     
       , m_toRowCol  (a_gb.gotoRC(aRow, aCol)) // pre-compute
       // other data attribute init
       {
          // ctor body
       }
      
      1. 使用预填充字符串在状态输出
      2. 之前定位光标
        m_gb.termUpdate(m_toRowCol + // position cursor
                        <output string>); // provide state info
        
相关问题