Windows C 控制台操作

 

获取标准输出句柄

要开始操作控制台,首先我们得获取到stdout的句柄。

HANDLE GetStdHandle(DWORD nStdHandle);

返回标准的输入、输出或错误的设备的句柄,也就是获得输入、输出/错误的屏幕缓冲区的句柄。

其中nStdHandle值为下面几种类型的一种:

STD_INPUT_HANDLESTD_OUTPUT_HANDLESTD_ERROR_HANDLE

分别代表标准输入,标准输出,错误输出。

程序结束之后会自动关闭句柄,但是一些大型应用可能要考虑一下释放句柄了

BOOL CloseHandle(HANDLE hObject);

获取当前控制台属性

在搞事情之前,保存一下控制台属性总是好的。

BOOL GetConsoleScreenBufferInfo (

HANDLE hConsoleOutput,

CONSOLE_SCREEN_BUFFER_INFO lpConsoleScreenBufferInfo);

CONSOLE_SCREEN_BUFFER_INFO是一个描述控制台属性的结构体,注意使用函数时需要传址来接收信息,其原型如下:

typedef struct _CONSOLE_SCREEN_BUFFER_INFO {

COORD dwSize; // 缓冲区大小

COORD dwCursorPosition; // 当前光标位置

WORD wAttributes; // 字符属性

SMALL_RECT srWindow; // 当前窗口显示的大小和位置

COORD dwMaximumWindowSize; // 最大的窗口缓冲区大小

} CONSOLE_SCREEN_BUFFER_INFO ;

基本上想要的都在这了。

控制台标题

DWORD GetConsoleTitle(LPTSTR lpConsoleTitle, DWORD nSize);

LPTSTR可以用普通char数组代替,nsize是接收的最大长度。

BOOL SetConsoleTitle(LPCTSTR lpConsoleTitle);

控制台操作例子

#include <windows.h>
#include <stdio.h>
#include <conio.h>
int main(void)
{
       char strTitle[255];
       CONSOLE_SCREEN_BUFFER_INFO bInfo; // 窗口缓冲区信息
       COORD size = {80, 25};
       HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE); // 获取标准输出设备句柄
       GetConsoleScreenBufferInfo(hOut, &bInfo ); // 获取窗口缓冲区信息
       GetConsoleTitle(strTitle, 255); // 获取窗口标题
       printf("当前窗口标题是:\n%s\n", strTitle);
       _getch();
       SetConsoleTitle("控制台窗口操作"); // 设置窗口标题
       GetConsoleTitle(strTitle, 255); 
       printf("当前窗口标题是:\n%s\n", strTitle);
       _getch();
       SetConsoleScreenBufferSize(hOut,size); // 重新设置缓冲区大小
       _getch();
       SMALL_RECT rc = {0,0, 80-1, 25-1}; // 重置窗口位置和大小
       SetConsoleWindowInfo(hOut,true ,&rc);
       CloseHandle(hOut); // 关闭标准输出设备句柄
       return 0;
}

文字颜色

既然是控制台,离不开的就是文字颜色了。windows提供的API叫做SetConsoleTextAttribute

一个小例子

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

int main()
{
    HANDLE h = GetStdHandle(STD_OUTPUT_HANDLE);
    WORD wOldColorAttrs;
    CONSOLE_SCREEN_BUFFER_INFO csbiInfo;

    // Save the current color
    GetConsoleScreenBufferInfo(h, &csbiInfo);
    wOldColorAttrs = csbiInfo.wAttributes;

    // Set the new color
    SetConsoleTextAttribute(h, FOREGROUND_RED | FOREGROUND_INTENSITY | BACKGROUND_GREEN);
    printf("This is a test\n");

    // Restore the original color
    SetConsoleTextAttribute(h, wOldColorAttrs);
    printf("This is a test\n");
}

BOOL SetConsoleTextAttribute(HANDLE hConsoleOutput, WORD wAttributes);

其中hConsoleOutput为我们上面获取到的句柄,wAttributes为颜色代码:

FOREGROUND_BLUE		字体颜色:蓝
FOREGROUND_GREEN	字体颜色:绿
FOREGROUND_RED		字体颜色:红
FOREGROUND_INTENSITY	前景色高亮显示
BACKGROUND_BLUE		背景颜色:蓝
BACKGROUND_GREEN	背景颜色:绿
BACKGROUND_RED		背景颜色:红
BACKGROUND_INTENSITY	背景色高亮显示

其颜色遵循三原色混合规律:

使用时将想要的参数用  |  (“按位或”)符号连接即可

 

想要恢复怎么办?CONSOLE_SCREEN_BUFFER_INFO里面有一个变量wAttributes(见上)储存的就是原来的颜色属性,需要时再用SetConsoleTextAttribute设置回来即可。

 

光标位置

储存光标位置的类型是COORD,对应CONSOLE_SCREEN_BUFFER_INFO.dwCursorPosition。

如果要设置光标位置使用SetConsoleCursorPosition

BOOL SetConsoleCursorPosition(HANDLE hConsoleOutput, COORD  dwCursorPosition);

COORD 原型如下:

typedef _COORD { short X, short Y} COORD;

一个小例子:

//C语言实现控制台中光标随意移动
#include <stdio.h>
#include <windows.h>
#include <conio.h>
  
HANDLE hout;
//获得输入
char getInput()
{
  int ch; //输入字符串
    
  COORD coord; //屏幕上的坐标
  CONSOLE_SCREEN_BUFFER_INFO csbi; //控制台屏幕缓冲区信息
  
  coord.X=10;
  coord.Y=10;
  
  ch=getch();
  
  //0x0d表示回车,0XE0表示上下左右等键的键码
  while(ch==0xE0||ch==0x0d)
  {
    GetConsoleScreenBufferInfo(hout,&csbi);
    coord.X=csbi.dwCursorPosition.X; //得到坐标X的值
    coord.Y=csbi.dwCursorPosition.Y; //得到坐标Y的值
    //如果是回车
    if(ch==0x0d)
    {
      coord.X=0;
      coord.Y++;
      SetConsoleCursorPosition(hout,coord);
      break;
    }
    ch=getch();
    //上
    if(ch==0x48)
    {
      if(coord.Y!=0)coord.Y--;
    }
    //下
    else if(ch==0x50)
    {
      coord.Y++;
    }
    //左
    else if(ch==0x4b)
    {
      if(coord.X!=0){coord.X--;}
    }
    //右
    else if(ch==0x4d)
    {
      if(coord.X!=79)coord.X++;
      else
      {
        coord.X=0;
        coord.Y++;
      }
    }
    SetConsoleCursorPosition(hout,coord);
    ch=getch();
  }
  return ch;
  }
int main()
{
  char ch;
  hout=GetStdHandle(STD_OUTPUT_HANDLE);
  //从键盘获取输入,如果是方向键则执行方向功能,如果是回车键则换行,如果是字符则输出
  while(1)
  {
    ch=getInput();
    printf("%c",ch);
  } 
  getchar(); 
}

光标

BOOL SetConsoleCursorInfo( // 设置光标信息

HANDLE hConsoleOutput, // 句柄

CONST CONSOLE_CURSOR_INFO *lpConsoleCursorInfo // 光标信息

);

 

BOOL GetConsoleCursorInfo( // 获取光标信息

HANDLE hConsoleOutput, // 句柄

PCONSOLE_CURSOR_INFO lpConsoleCursorInfo // 返回光标信息

);

这两个函数都与CONSOLE_CURSOR_INFO结构体类型有关,其定义如下:

typedef struct _CONSOLE_CURSOR_INFO {

DWORD dwSize; // 光标百分比大小

BOOL bVisible; // 是否可见

} CONSOLE_CURSOR_INFO, *PCONSOLE_CURSOR_INFO;

dwSize值反映了光标的大小,它的值范围为1-100;当为1时,光标最小,仅是一条最靠下的水平细线,当为100,光标最大,为一个字符大小的方块。

文本输出

BOOL FillConsoleOutputCharacter( // 填充指定数据的字符

HANDLE hConsoleOutput, // 句柄

TCHAR cCharacter, // 字符

DWORD nLength, // 字符个数

COORD dwWriteCoord, // 起始位置

LPDWORD lpNumberOfCharsWritten);// (接收,需传址)已写个数

 

BOOL WriteConsole( // 在当前光标位置处插入指定数量的字符

HANDLE hConsoleOutput, // 句柄

CONST VOID *lpBuffer, // 字符串

DWORD nNumberOfCharsToWrite, // 字符个数

LPDWORD lpNumberOfCharsWritten, // (接收,需传址)已写个数

LPVOID lpReserved);// 保留

 

BOOL WriteConsoleOutput( // 向指定区域写带属性的字符

HANDLE hConsoleOutput, // 句柄

CONST CHAR_INFO *lpBuffer, // 字符数据区

COORD dwBufferSize, // 数据区大小

COORD dwBufferCoord, // 起始坐标

PSMALL_RECT lpWriteRegion );// 限定要写的区域(超出自动换行)

 

BOOL WriteConsoleOutputCharacter( // 在指定位置处插入指定数量的字符

HANDLE hConsoleOutput, // 句柄

LPCTSTR lpCharacter, // 字符串

DWORD nLength, // 字符个数

COORD dwWriteCoord, // 起始位置

LPDWORD lpNumberOfCharsWritten); // (接收,需传址)已写个数

文本操作例子 

// 在具有阴影效果的窗口中显示一行字符
#include <windows.h>
HANDLE hOut;
void ShadowWindowLine(char *str); 
void DrawBox(bool bSingle, SMALL_RECT rc); // 绘制边框
int main(void)
{
       hOut = GetStdHandle(STD_OUTPUT_HANDLE); // 获取标准输出设备句柄
       SetConsoleOutputCP(437); // 设置代码页,这里如果设置成936(简体中文),那么程序会怎样?那样的话,将画不出边框。
       ShadowWindowLine("Display a line of words, and center the window with shadow.");
       CloseHandle(hOut); // 关闭标准输出设备句柄
       return 0;
}
void ShadowWindowLine(char *str)
{
       SMALL_RECT rc;
       CONSOLE_SCREEN_BUFFER_INFO bInfo; // 窗口缓冲区信息
       WORD att0,att1,attText;
       int i, chNum = strlen(str);
       GetConsoleScreenBufferInfo( hOut, &bInfo ); // 获取窗口缓冲区信息
       // 计算显示窗口大小和位置
       rc.Left = (bInfo.dwSize.X - chNum)/2 - 2;
       rc.Top = 8; // 原代码段中此处为bInfo.dwSize.Y/2 - 2,但是如果您的DOS屏幕有垂直滚动条的话,还需要把滚动条下拉才能看到,为了方便就把它改为10
       rc.Right = rc.Left + chNum + 4;
       rc.Bottom = rc.Top + 4;
       att0 = BACKGROUND_INTENSITY; // 阴影属性
       att1 = FOREGROUND_RED |FOREGROUND_GREEN |FOREGROUND_BLUE | FOREGROUND_INTENSITY | BACKGROUND_RED | BACKGROUND_BLUE;// 文本属性
       attText = FOREGROUND_RED |FOREGROUND_INTENSITY; // 文本属性
       // 设置阴影然后填充
       COORD posShadow = {rc.Left+1, rc.Top+1}, posText = {rc.Left, rc.Top};
       for (i=0; i<5; i++)
       {
              FillConsoleOutputAttribute(hOut, att0, chNum + 4, posShadow, NULL);
              posShadow.Y++;
       }
       for (i=0;i<5;i++)
       {
              FillConsoleOutputAttribute(hOut, att1,chNum + 4, posText, NULL);
              posText.Y++;
       }
       // 写文本和边框
       posText.X = rc.Left + 2;
       posText.Y = rc.Top + 2;
       WriteConsoleOutputCharacter(hOut, str, strlen(str), posText, NULL);
       DrawBox(true, rc);
       SetConsoleTextAttribute(hOut, bInfo.wAttributes); // 恢复原来的属性
}
void DrawBox(bool bSingle, SMALL_RECT rc) // 函数功能:画边框
{
       char chBox[6];
       COORD pos;
       if (bSingle) 
       {
              chBox[0] = (char)0xda; // 左上角点
              chBox[1] = (char)0xbf; // 右上角点
              chBox[2] = (char)0xc0; // 左下角点
              chBox[3] = (char)0xd9; // 右下角点
              chBox[4] = (char)0xc4; // 水平
              chBox[5] = (char)0xb3; // 坚直
       } else {
              chBox[0] = (char)0xc9; // 左上角点
              chBox[1] = (char)0xbb; // 右上角点
              chBox[2] = (char)0xc8; // 左下角点
              chBox[3] = (char)0xbc; // 右下角点
              chBox[4] = (char)0xcd; // 水平
              chBox[5] = (char)0xba; // 坚直
       }
       // 画边框的上 下边界
       for(pos.X = rc.Left+1;pos.X<rc.Right-1;pos.X++)
       {     
              pos.Y = rc.Top;
              // 画上边界
              WriteConsoleOutputCharacter(hOut, &chBox[4], 1, pos, NULL);
              // 画左上角
              if(pos.X == rc.Left+1)
              {
                     pos.X--;
                     WriteConsoleOutputCharacter(hOut, &chBox[0],1, pos, NULL);
                     pos.X++;
              }
              // 画右上角
              if(pos.X == rc.Right-2)
              {
                     pos.X++;
                     WriteConsoleOutputCharacter(hOut, &chBox[1], 1, pos, NULL);
                     pos.X--;
              }
              pos.Y = rc.Bottom;
              // 画下边界
              WriteConsoleOutputCharacter(hOut, &chBox[4], 1, pos, NULL);
              // 画左下角
              if(pos.X == rc.Left+1)
              {
                     pos.X--;
                     WriteConsoleOutputCharacter(hOut, &chBox[2], 1, pos, NULL);
                     pos.X++;
              }
              // 画右下角
              if(pos.X==rc.Right-2)
              {
                     pos.X++;
                     WriteConsoleOutputCharacter(hOut, &chBox[3], 1, pos, NULL);
                     pos.X--;
              }
       }
       // 画边框的左右边界
       for (pos.Y = rc.Top+1; pos.Y<=rc.Bottom-1; pos.Y++)
       {
              pos.X = rc.Left;
              // 画左边界
              WriteConsoleOutputCharacter(hOut, &chBox[5], 1, pos, NULL);
              pos.X = rc.Right-1;
              // 画右边界
              WriteConsoleOutputCharacter(hOut, &chBox[5], 1, pos, NULL);
       }
}

效果图

 

转载于:https://my.oschina.net/u/2933242/blog/1491751

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值