首页 > 编程语言 > 详细

C语言控制台窗口图形界面编程

时间:2020-05-25 14:56:07      阅读:103      评论:0      收藏:0      [点我收藏+]

句柄

在Windows操作系统下用C语言编写控制台的窗口界面首先要获取当前标准输入和标准输出设备的句柄。“句柄”是Windows最常用的一个概念。它通常用来标识Windows资源(如菜单、 图标、窗口等)和设备等对象。虽然可以把句柄理解为是一个指针变量类型,但它不是对象所在的地址指针,而是作为Windows系统内部表的索引值来使用 的。调用相关文本界面控制的API函数。这些函数可分为三类。

  1. 用于控制台窗口操作的函数(包括窗口的缓冲区大小、窗口前景字符和背景颜色、窗口标题、大小和位置等);
  2. 用于控制台输入输出的函数(包括字符属性操作函数);
  3. 其他的函数并为最后一类。通过调用CloseHandle函数来关闭输入输出句柄。

通过调用函数GetStdHandle可以获取当前标准输入以及输出设备的句柄。函数原型为:

HANDLE GetStdHandle(DWORD nStdHandle); 

其中,nStdHandle可以是:

  • STD_INPUT_HANDLE    标准输入设备句柄 
  • STD_OUTPUT_HANDLE   标准输出设备句柄 
  • STD_ERROR_HANDLE    标准错误设备句柄 

用于控制台窗口操作的API函数

GetConsoleScreenBufferInfo(); //获取控制台窗口信息
GetConsoleTitle();              //获取控制台窗口标题
SetConsoleScreenBufferSize(); //更改指定缓冲区大小
SetConsoleTitle();              //设置控制台窗口标题
SetConsoleWindowInfo();          //设置控制台窗口信息

举个例子:

#include <stdio.h>
#include <stdlib.h>
#include <Windows.h>
#include <conio.h>
#define N 255
int main()
{
    HANDLE handle_out;                 //定义一个句柄
    CONSOLE_SCREEN_BUFFER_INFO scbi; //定义一个窗口缓冲区信息结构体
    COORD size = {80, 25};             //定义一个坐标结构体
    char strtitle[N];
    handle_out = GetStdHandle(STD_OUTPUT_HANDLE);  //获得标准输出设备句柄
    GetConsoleScreenBufferInfo(handle_out, &scbi); //获得窗口缓冲区信息
    GetConsoleTitle(strtitle, N);                   //获得当前窗口标题
    printf("当前窗口标题为:%s\n", strtitle);
    _getch();
    SetConsoleTitle("控制台窗口操作"); //设置窗口标题为“控制台窗口操作”
    GetConsoleTitle(strtitle, N);       //获得当前窗口标题
    printf("当前窗口标题为:%s\n", strtitle);
    _getch();
    SetConsoleScreenBufferSize(handle_out, size); // 重新设置缓冲区大小
    _getch();
    SMALL_RECT rc = {0, 0, 80 - 1, 25 - 1}; // 重置窗口位置和大小
    SetConsoleWindowInfo(handle_out, 1, &rc);
    CloseHandle(handle_out); //关闭标准输出设备句柄
    system("pause");
    return 0;
}

 技术分享图片技术分享图片

设置文本属性的函数

BOOL SetConsoleTextAttribute( // 设置WriteConsole等函数的字符属性
    HANDLE hConsoleOutput,      // 句柄
    WORD wAttributes          // 文本属性
);

文本属性,其实就是颜色属性,有背景色和前景色(就是字符的颜色)两类,每一类只提供三原色(红,绿,蓝)和加强色(灰色,可与其他颜色搭配使用,使颜色变亮。

基本文本属性:

  • FOREGROUND_BLUE 蓝色 
  • FOREGROUND_GREEN 绿色 
  • FOREGROUND_RED 红色 
  • FOREGROUND_INTENSITY 加强 
  • BACKGROUND_BLUE 蓝色背景 
  • BACKGROUND_GREEN 绿色背景 
  • BACKGROUND_RED 红色背景 
  • BACKGROUND_INTENSITY 背景色加强 
  • COMMON_LVB_REVERSE_VIDEO 反色 

 举个例子:

#include <windows.h>
#include <iostream>
using namespace std;
int main()
{
    HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);

    SetConsoleTextAttribute(handle, FOREGROUND_RED);
    cout << "Red     " << flush;
    SetConsoleTextAttribute(handle, FOREGROUND_RED | FOREGROUND_INTENSITY);
    cout << "Red" << endl;

    SetConsoleTextAttribute(handle, FOREGROUND_GREEN);
    cout << "Green   " << flush;
    SetConsoleTextAttribute(handle, FOREGROUND_GREEN | FOREGROUND_INTENSITY);
    cout << "Green" << endl;

    SetConsoleTextAttribute(handle, FOREGROUND_BLUE);
    cout << "Blue    " << flush;
    SetConsoleTextAttribute(handle, FOREGROUND_BLUE | FOREGROUND_INTENSITY);
    cout << "Blue" << endl;

    SetConsoleTextAttribute(handle, FOREGROUND_RED | FOREGROUND_GREEN);
    cout << "Yellow  " << flush;
    SetConsoleTextAttribute(handle, FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_INTENSITY);
    cout << "Yellow" << endl;

    SetConsoleTextAttribute(handle, FOREGROUND_GREEN | FOREGROUND_BLUE);
    cout << "Cyan    " << flush;
    SetConsoleTextAttribute(handle, FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY);
    cout << "Cyan" << endl;

    SetConsoleTextAttribute(handle, FOREGROUND_BLUE | FOREGROUND_RED);
    cout << "Magenta " << flush;
    SetConsoleTextAttribute(handle, FOREGROUND_BLUE | FOREGROUND_RED | FOREGROUND_INTENSITY);
    cout << "Magenta" << endl;

    SetConsoleTextAttribute(handle, FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
    cout << "White   " << flush;
    SetConsoleTextAttribute(handle, FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY);
    cout << "White" << endl;
    system("pause");
    return 0;
}

技术分享图片

#include <windows.h>
#include <iostream>
using namespace std;
int main()
{
    HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);

    SetConsoleTextAttribute(handle, BACKGROUND_RED);
    cout << "Red     " << flush;
    SetConsoleTextAttribute(handle, BACKGROUND_RED | BACKGROUND_INTENSITY);
    cout << "Red     " << endl;

    SetConsoleTextAttribute(handle, BACKGROUND_GREEN);
    cout << "Green   " << flush;
    SetConsoleTextAttribute(handle, BACKGROUND_GREEN | BACKGROUND_INTENSITY);
    cout << "Green   " << endl;

    SetConsoleTextAttribute(handle, BACKGROUND_BLUE);
    cout << "Blue    " << flush;
    SetConsoleTextAttribute(handle, BACKGROUND_BLUE | BACKGROUND_INTENSITY);
    cout << "Blue    " << endl;

    SetConsoleTextAttribute(handle, BACKGROUND_RED | BACKGROUND_GREEN);
    cout << "Yellow  " << flush;
    SetConsoleTextAttribute(handle, BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_INTENSITY);
    cout << "Yellow  " << endl;

    SetConsoleTextAttribute(handle, BACKGROUND_GREEN | BACKGROUND_BLUE);
    cout << "Cyan    " << flush;
    SetConsoleTextAttribute(handle, BACKGROUND_GREEN | BACKGROUND_BLUE | BACKGROUND_INTENSITY);
    cout << "Cyan    " << endl;

    SetConsoleTextAttribute(handle, BACKGROUND_BLUE | BACKGROUND_RED);
    cout << "Magenta " << flush;
    SetConsoleTextAttribute(handle, BACKGROUND_BLUE | BACKGROUND_RED | BACKGROUND_INTENSITY);
    cout << "Magenta " << endl;

    SetConsoleTextAttribute(handle, BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE);
    cout << "White   " << flush;
    SetConsoleTextAttribute(handle, BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE | BACKGROUND_INTENSITY);
    cout << "White   " << endl;
    system("pause");
    return 0;
}

技术分享图片

常用的文本输出函数

BOOL FillConsoleOutputAttribute(   // 填充字符属性
    HANDLE hConsoleOutput,           // 句柄
    WORD wAttribute,               // 文本属性
    DWORD nLength,                   // 个数
    COORD dwWriteCoord,               // 开始位置
    LPDWORD lpNumberOfAttrsWritten // 返回填充的个数
);
BOOL FillConsoleOutputCharacter(   // 填充指定数据的字符
    HANDLE hConsoleOutput,           // 句柄
    TCHAR cCharacter,               // 字符
    DWORD nLength,                   // 字符个数
    COORD dwWriteCoord,               // 起始位置
    LPDWORD lpNumberOfCharsWritten // 已写个数
);
BOOL WriteConsoleOutputCharacter(  // 在指定位置处插入指定数量的字符
    HANDLE hConsoleOutput,           // 句柄
    LPCTSTR lpCharacter,           // 字符串
    DWORD nLength,                   // 字符个数
    COORD dwWriteCoord,               // 起始位置
    LPDWORD lpNumberOfCharsWritten // 已写个数
);

 举个例子:

#include <stdio.h>
#include <stdlib.h>
#include <Windows.h>
#include <conio.h>

int main()
{
    char *str = "Hello World!"; //定义输出信息
    int len = strlen(str), i;
    WORD shadow = BACKGROUND_INTENSITY;                     //阴影属性
    WORD text = BACKGROUND_GREEN | BACKGROUND_INTENSITY; //文本属性
    HANDLE handle_out = GetStdHandle(STD_OUTPUT_HANDLE); //获得标准输出设备句柄
    CONSOLE_SCREEN_BUFFER_INFO csbi;                     //定义窗口缓冲区信息结构体
    GetConsoleScreenBufferInfo(handle_out, &csbi);         //获得窗口缓冲区信息
    SMALL_RECT rc;                                         //定义一个文本框输出区域
    COORD posText;                                         //定义文本框的起始坐标
    COORD posShadow;                                     //定义阴影框的起始坐标
    //确定区域的边界
    rc.Top = 8;                                 //上边界
    rc.Bottom = rc.Top + 4;                     //下边界
    rc.Left = (csbi.dwSize.X - len) / 2 - 2; //左边界,为了让输出的字符串居中
    rc.Right = rc.Left + len + 4;             //右边界
    //确定文本框起始坐标
    posText.X = rc.Left;
    posText.Y = rc.Top;
    //确定阴影框的起始坐标
    posShadow.X = posText.X + 1;
    posShadow.Y = posText.Y + 1;
    for (i = 0; i < 5; ++i) //先输出阴影框
    {
        FillConsoleOutputAttribute(handle_out, shadow, len + 4, posShadow, NULL);
        posShadow.Y++;
    }
    for (i = 0; i < 5; ++i) //在输出文本框,其中与阴影框重合的部分会被覆盖掉
    {
        FillConsoleOutputAttribute(handle_out, text, len + 4, posText, NULL);
        posText.Y++;
    }
    //设置文本输出处的坐标
    posText.X = rc.Left + 2;
    posText.Y = rc.Top + 2;
    WriteConsoleOutputCharacter(handle_out, str, len, posText, NULL); //输出字符串
    SetConsoleTextAttribute(handle_out, csbi.wAttributes);              // 恢复原来的属性
    CloseHandle(handle_out);
    return 0;
}

技术分享图片

控制文本移动的函数

BOOL ScrollConsoleScreenBuffer(             //文本移动函数
    HANDLE hConsoleOutput,                 //句柄
    const SMALL_RECT *lpScrollRectangle, //移动区域
    const SMALL_RECT *lpClipRectangle,     //裁剪区域,如果为NULL,那么将代表整个屏幕缓冲区
    COORD dwDestinationOrigin,             //移动到的位置,这个点将成为移动区域的左上顶点
    const CHAR_INFO *lpFill                 //空出区域的填充字符
);

举个例子:

#include <stdio.h>
#include <conio.h>
#include <Windows.h>
#include <stdlib.h>
int main()
{
    HANDLE handle_out = GetStdHandle(STD_OUTPUT_HANDLE); //获得标准输出设备句柄
    CONSOLE_SCREEN_BUFFER_INFO csbi;                     //定义窗口缓冲区信息结构体
    SMALL_RECT scroll;                                     //定义移动区域
    COORD pos = {0, 5};                                     //移动位置
    CHAR_INFO chFill;                                     //定义填充字符
    GetConsoleScreenBufferInfo(handle_out, &csbi);         //获得窗口缓冲区信息
    //定义填充字符的各个参数及属性
    chFill.Char.AsciiChar =  ;
    chFill.Attributes = csbi.wAttributes;
    //输出文本
    printf("00000000000000000000000000000\n");
    printf("11111111111111111111111111111\n");
    printf("22222222222222222222222222222\n");
    printf("33333333333333333333333333333\n");
    //确定区域
    scroll.Left = 1;
    scroll.Top = 1;
    scroll.Right = 10;
    scroll.Bottom = 2;
    ScrollConsoleScreenBuffer(handle_out, &scroll, NULL, pos, &chFill); //移动文本
    return 0;
}

技术分享图片

 在上面的样例程序中,裁剪区域是整个控制台窗口的屏幕缓冲区,现在如果我们把裁剪区域设定为与移动区域一样,也就是说ScrollConsoleScreenBuffer函数的第三个参数也改成&scroll,那么结果会怎么样呢?

技术分享图片

 现在我们应该可以猜想出结论了,别急,再做一个实验,现在我们将裁减区域又重新改为整个屏幕缓冲区,看看会有什么样的现象发生?

技术分享图片

 再来最后一个实验,我们将裁减区域减小为移动区域的上半部分,继续执行下移一行的操作,看看最终结果会怎么样?

技术分享图片

 好了,现在我们通过归纳可以得出几个结论了,那就是

  • 裁减区域以外的区域不会受文本移动的影响。具体是:
  1. 裁减区域以外的区域不会被移动过来的区域覆盖,
  2. 裁减区域以外的区域被移动到他处之后原区域不发生变化,因此不需要填充字符。

总的归纳来说也就是原来是什么样子,文本移动后还是什么样子,不会改变。

  • 裁减区域以内的区域受文本移动的影响。具体是:
  1. 当裁减区域以内的区域被移动到他处造成该区域为空时会被设定的字符填充,
  2. 裁减区域以内的区域会被移动过来的区域覆盖。

总的归纳来说也就是完全受文本移动的影响,移动过来就被覆盖,被移走就由设定的字符来填充。

当然移动文本还有很多好玩的操作,比如说和sleep() 结合在一起做成控制台小动画。

#include <iostream>
#include <algorithm>
#include <windows.h>
#include <iomanip>
#include <conio.h>
#include "date.cpp"
#define stoptimeshort 40
#define stoptimelong 100
using namespace std;
int main()
{
    string elemode[2] = {"██████████████████████████████", "██                                                    ██"};
    for (int i = 0; i < 30; i++)
    {
        cout << elemode[1] << endl;
    }
    cout << elemode[0] << endl;
    HANDLE handle_out = GetStdHandle(STD_OUTPUT_HANDLE);
    CONSOLE_SCREEN_BUFFER_INFO csbi;               //定义窗口缓冲区信息结构体
    SMALL_RECT scroll;                             //定义移动区域
    COORD pos = {26, 0};                           //移动位置
    CHAR_INFO chFill;                              //定义填充字符
    GetConsoleScreenBufferInfo(handle_out, &csbi); //获得窗口缓冲区信息
    //定义填充字符的各个参数及属性
    chFill.Char.AsciiChar =  ;
    chFill.Attributes = csbi.wAttributes;
    for (int i = 2; i < 28; i += 2)
    {
        Sleep(stoptimelong);
        pos = {i + 2, 0};
        scroll.Left = i;
        scroll.Top = 0;
        scroll.Right = i + 1;
        scroll.Bottom = 29;
        ScrollConsoleScreenBuffer(handle_out, &scroll, NULL, pos, &chFill); //移动文本
        pos = {56 - i, 0};
        scroll.Left = 58 - i;
        scroll.Top = 0;
        scroll.Right = 59 - i;
        scroll.Bottom = 29;
        ScrollConsoleScreenBuffer(handle_out, &scroll, NULL, pos, &chFill); //移动文本
    }
    //关闭标准输出设备句柄
    CloseHandle(handle_out);
    system("pause");
    return 0;
}

 控制光标位置的函数

BOOL SetConsoleCursorPosition( //设置光标位置
    HANDLE hConsoleOutput,       //句柄
    COORD dwCursorPosition       //坐标
);                               //若函数调用成功则返回非0值
BOOL GetConsoleCursorInfo(                     //获得光标信息
    HANDLE hConsoleOutput,                     //句柄
    PCONSOLE_CURSOR_INFO lpConsoleCursorInfo //光标信息,注意这是个指针类型
);
BOOL SetConsoleCursorInfo(                           //设置光标信息
    HANDLE hConsoleOutput,                           //句柄
    const CONSOLE_CURSOR_INFO *lpConsoleCursorInfo //光标信息
);

举个例子:

#include <stdio.h>
#include <Windows.h>
#include <conio.h>
#include <stdlib.h>
int main()
{
    HANDLE handle_out = GetStdHandle(STD_OUTPUT_HANDLE); //获得标准输出设备句柄
    CONSOLE_CURSOR_INFO cci;                             //定义光标信息结构体
    GetConsoleCursorInfo(handle_out, &cci);                 //获得当前光标信息
    cci.dwSize = 100; //设置光标尺寸为100
    SetConsoleCursorInfo(handle_out, &cci);
    _getch();
    cci.bVisible = false; //设置光标为不可见
    SetConsoleCursorInfo(handle_out, &cci);
    _getch();
    return 0;
}

技术分享图片

键盘事件函数

BOOL ReadConsoleInput(             //读取输入信息
    HANDLE hConsoleInput,         //句柄
    PINPUT_RECORD lpBuffer,         //输入事件结构体的指针
    DWORD nLength,                 //要读取的记录数
    LPDWORD lpNumberOfEventsRead //用来接受成功读取记录数的指针
);                                 //如果该函数成功调用,返回非零值
                                 //输入事件结构体的指针可以是结构体数组的首地址,这样就可以一次性读取多个记录数。

 举个例子:

#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include <conio.h>
#define true 1
#define false 0
int main()
{
    HANDLE handle_in = GetStdHandle(STD_INPUT_HANDLE); //获得标准输入设备句柄
    INPUT_RECORD keyrec;                               //定义输入事件结构体
    DWORD res;                                           //定义返回记录
    for (;;)
    {
        ReadConsoleInput(handle_in, &keyrec, 1, &res); //读取输入事件
        if (keyrec.EventType == KEY_EVENT)               //如果当前事件是键盘事件
        {
            /*    当你按下Esc键后又马上释放,程序会输出两次Esc,因为有两次事件的虚拟键代码都是Esc键的代码,一次是按下,一次是释放。
                如果要实现按下键后出现反应,释放不出现反应可以将判断语句改成
                if (keyrec.Event.KeyEvent.wVirtualKeyCode == VK_ESCAPE  && keyrec.Event.KeyEvent.bKeyDown == true)     
                //表示当前为键按下而不是键释放 */
            if (keyrec.Event.KeyEvent.wVirtualKeyCode == VK_ESCAPE) //当前事件的虚拟键为Esc键
            {
                printf("Esc ");
            }
        }
    }
    system("pause");
    return 0;
}

鼠标事件函数

#include <stdio.h>  
#include <windows.h>  
#include <conio.h>  
  
HANDLE handle_in;  
HANDLE handle_out;  
CONSOLE_SCREEN_BUFFER_INFO csbi;        //定义窗口缓冲区信息结构体  
  
void DisplayMousePosition(COORD pos);   //显示鼠标所在位置  
  
void gotoxy(int x, int y);  //将光标移到坐标为(x,y)的位置  
  
int main()  
{  
    handle_in = GetStdHandle(STD_INPUT_HANDLE);      //获得标准输入设备句柄  
    handle_out = GetStdHandle(STD_OUTPUT_HANDLE);    //获得标准输出设备句柄  
    INPUT_RECORD mouserec;      //定义输入事件结构体  
    DWORD res;      //用于存储读取记录  
    COORD pos;      //用于存储鼠标当前位置  
    COORD size = {80, 25};  //窗口缓冲区大小  
    GetConsoleScreenBufferInfo(handle_out, &csbi);  //获得窗口缓冲区信息  
    SetConsoleScreenBufferSize(handle_out, size);   //设置窗口缓冲区大小  
    for (;;)  
    {  
        ReadConsoleInput(handle_in, &mouserec, 1, &res);      //读取输入事件  
        pos = mouserec.Event.MouseEvent.dwMousePosition;    //获得当前鼠标位置  
        gotoxy(0, 24);  //在第25行显示鼠标位置  
        DisplayMousePosition(pos);      //显示鼠标位置  
        if (mouserec.EventType == MOUSE_EVENT)    //如果当前为鼠标事件  
        {  
            gotoxy(pos.X, pos.Y);  
            //单击鼠标左键,输出字符A  
            if (mouserec.Event.MouseEvent.dwButtonState == FROM_LEFT_1ST_BUTTON_PRESSED)  
            {  
                putchar(A);  
            }  
            //单击鼠标右键,输出字符B  
            if (mouserec.Event.MouseEvent.dwButtonState == RIGHTMOST_BUTTON_PRESSED)  
            {  
                putchar(B);  
            }  
            //双击退出  
            if (mouserec.Event.MouseEvent.dwEventFlags == DOUBLE_CLICK)  
            {  
                break;  
            }  
        }  
    }  
    CloseHandle(handle_out);  
    CloseHandle(handle_in);  
    return 0;  
}  
  
void DisplayMousePosition(COORD pos)  
{  
    COORD dis = {0, 24};        //在第24行显示鼠标位置  
    WORD att = FOREGROUND_GREEN | FOREGROUND_INTENSITY; //文本属性  
    GetConsoleScreenBufferInfo(handle_out, &csbi);  //获得窗口缓冲区信息  
    printf("X = %3d, Y = %3d", (int)pos.X, (int)pos.Y);  
    FillConsoleOutputAttribute(handle_out, att, 16, dis, NULL);  //填充文本属性  
    return;  
}  
  
void gotoxy(int x, int y)  
{  
    COORD pos = {x, y};  
    SetConsoleCursorPosition(handle_out, pos);  
}  

技术分享图片

 

 

 

 

C语言控制台窗口图形界面编程

原文:https://www.cnblogs.com/stu-jyj3621/p/12956366.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!