控制台基础概念实例
上一篇文章 控制台基础概念 介绍了控制的基本构成,以及一些操作处理。这一部分以实际代码为主,给出控制台使用的几个例子。
以main函数作为入口函数的程序都是控制台程序,最简单的控制台程序就是Hello World的程序。这里不给出了。
GUI程序可以使用以下几种方式使用控制台:
- 在调用CreateProcess时使用CREATE_NEW_CONSOLE标志。(默认情况下,待启动进程为控制台程序时不推荐使用该参数,因为无法确定用户输入是有哪个控制台处理的)
- 通过 AttachConsole函数附加到一个已经存在的控制台。
- 未附加到控制台的程序可通过AllocConsole函数创建控制台。(GUI进程默认不会和控制台关联。若使用DETACHED_PROCESS参数调用CreateProcess启动一个控制台进程,则会创建一个无控制台的控制台进程。)
GUI程序可使用FreeConsole函数来释放控制台。一个控制台程序可以通过GetConsoleProcessList函数获取所有与其关联的进程列表。
控制台程序提供以下函数,用于改变控制台属性:
GetConsoleScreenBufferInfo | 获得窗口大小、屏幕缓冲大小和颜色属性 |
SetConsoleWindowInfo | 设置控制台窗口大小 |
SetConsoleScreenBufferSize | 设置控制台屏幕缓冲大小 |
SetConsoleTextAttribute | 设置控制台字符属性 |
SetConsoleTitle | 设置控制台标题 |
GetConsoleTitle | 获取控制台标题 |
实例a 控制台参数获取及设置
本实例说明如何获取和设置控制台相关参数,例如设置和获取标题栏、设置和获取控制台显示窗口位置等。
代码如下:
// 显示及设置控制台相关参数 // 1. 设置及获取控制台标题栏 // 2. 获取屏幕输出缓冲的参数 // 3. 设置控制台窗口大小 // 4. 设置控制台屏幕缓冲大小 // 建议使用visual studio 2005以上版本编译,使用unicode编码 #include <windows.h> #include <iostream> using std::wcout; using std::endl; int _tmain(int argc, _TCHAR* argv[]) { std::wcout.imbue(std::locale("chs")); // 获取和设置控制台标题栏 DWORD title_need_size = 1024; // 64k TCHAR * console_title = new TCHAR[title_need_size+1]; memset(console_title, 0, (title_need_size+1)*sizeof(TCHAR)); DWORD title_size = GetConsoleTitle(console_title, title_need_size); if (0 == title_size) { wcout << "调用GetConsoleTitle异常,错误码"<< GetLastError() << endl; delete [] console_title; return 0; } wcout << _T("控制台标题栏") << console_title << endl; SetConsoleTitle(_T("ShowConsoleInfo")); wcout << endl << endl; HANDLE stdOutHandle = GetStdHandle(STD_OUTPUT_HANDLE); if (INVALID_HANDLE_VALUE == stdOutHandle) { wcout << "调用GetStdHandle失败,错误码" << GetLastError() << endl; return 0; } // 获取屏幕缓冲信息 CONSOLE_SCREEN_BUFFER_INFO console_screen_buff_info; memset(&console_screen_buff_info, 0, sizeof(CONSOLE_SCREEN_BUFFER_INFO)); if (GetConsoleScreenBufferInfo(stdOutHandle, &console_screen_buff_info)) { wcout << _T("屏幕缓冲大小:列数x行数") << console_screen_buff_info.dwSize.X << _T("x") << console_screen_buff_info.dwSize.Y << endl; wcout << _T("控制台光标位置(x,y):(") << console_screen_buff_info.dwCursorPosition.X << _T(",") << console_screen_buff_info.dwCursorPosition.Y << _T(")") << endl; wcout << _T("屏幕缓冲字符属性: ") << std::hex << console_screen_buff_info.wAttributes << endl; wcout << _T("屏幕缓冲显示窗口位置left:") << console_screen_buff_info.srWindow.Left << _T(" Right:") << console_screen_buff_info.srWindow.Right << _T(" Top:") << console_screen_buff_info.srWindow.Top << _T(" Bottom:") << console_screen_buff_info.srWindow.Bottom <<endl; wcout << _T("最大显示窗口大小:") << console_screen_buff_info.dwMaximumWindowSize.X << _T("x") << console_screen_buff_info.dwMaximumWindowSize.Y << endl; } // 下面设置需要将控制台屏幕缓冲窗口下移三行,用于移除关于设置控制台标题提示 SMALL_RECT sRect; sRect.Left = 0; sRect.Right = 0; sRect.Top = 3; sRect.Bottom = 3; if (!SetConsoleWindowInfo(stdOutHandle, FALSE, &sRect)) { wcout << "调用SetConsoleWindowInfo失败,错误码" << GetLastError() << endl; return 0; } // 以上代码是控制台滚屏的一种实现方式,可考虑扩展下 // msdn上的例子 // http://msdn.microsoft.com/en-us/library/windows/desktop/ms685118(v=vs.85).aspx // 可使用SetConsoleScreenBufferSize来设置屏幕缓冲大小 return 0; }
实例b GUI程序创建控制台及销毁
可以使用本实例的方法,在GUI程序中使用控制台调试跟踪相关问题。
最终运行效果如下图,GUI程序界面+后台的Console界面
代码如下:
// GUI程序创建控制台示例代码,1_bGuiAllocConsole // GUI程序可以使用AttachConsole函数与某个已经存在的控制台关联,需要预先知道该进程pid // 本demo展示了如何使用Alloc创建控制台,主要代码位于WM_CREATE、WM_DESTORY消息处理中 // 编译建议使用visual studio 2010 类型win32,使用unicode编码 #include <iostream> // 全局变量: HINSTANCE hInst; // 当前实例 TCHAR szTitle[] = _T("win32Test");// 标题栏文本 TCHAR szWindowClass[]= _T("WIN32TEST");// 主窗口类名 // 此代码模块中包含的函数的前向声明: ATOM MyRegisterClass(HINSTANCE hInstance); BOOL InitInstance(HINSTANCE, int); LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); int APIENTRY _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow) { UNREFERENCED_PARAMETER(hPrevInstance); UNREFERENCED_PARAMETER(lpCmdLine); std::wcout.imbue(std::locale("chs")); MyRegisterClass(hInstance); // 执行应用程序初始化: if (!InitInstance (hInstance, nCmdShow)) { return FALSE; } MSG msg; // 主消息循环: while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return (int) msg.wParam; } // // 函数: MyRegisterClass() // // 目的: 注册窗口类。 // // 注释: // // 仅当希望 // 此代码与添加到 Windows 95 中的“RegisterClassEx” // 函数之前的 Win32 系统兼容时,才需要此函数及其用法。调用此函数十分重要, // 这样应用程序就可以获得关联的 // “格式正确的”小图标。 // ATOM MyRegisterClass(HINSTANCE hInstance) { WNDCLASSEX wcex; wcex.cbSize = sizeof(WNDCLASSEX); wcex.style = CS_HREDRAW | CS_VREDRAW; wcex.lpfnWndProc = WndProc; wcex.cbClsExtra = 0; wcex.cbWndExtra = 0; wcex.hInstance = hInstance; wcex.hIcon = NULL; wcex.hCursor = LoadCursor(NULL, IDC_ARROW); wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); wcex.lpszMenuName = NULL; wcex.lpszClassName = szWindowClass; wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL)); return RegisterClassEx(&wcex); } // // 函数: InitInstance(HINSTANCE, int) // // 目的: 保存实例句柄并创建主窗口 // // 注释: // // 在此函数中,我们在全局变量中保存实例句柄并 // 创建和显示主程序窗口。 // BOOL InitInstance(HINSTANCE hInstance, int nCmdShow) { HWND hWnd; hInst = hInstance; // 将实例句柄存储在全局变量中 hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL); if (!hWnd) { return FALSE; } ShowWindow(hWnd, nCmdShow); UpdateWindow(hWnd); return TRUE; } // // 函数: WndProc(HWND, UINT, WPARAM, LPARAM) // // 目的: 处理主窗口的消息。 // // WM_COMMAND - 处理应用程序菜单 // WM_PAINT - 绘制主窗口 // WM_DESTROY - 发送退出消息并返回 // // LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { PAINTSTRUCT ps; HDC hdc; static RECT rcText = {10,10,300,100}; switch (message) { case WM_PAINT: hdc = BeginPaint(hWnd, &ps); // TODO: 在此添加任意绘图代码... DrawText(hdc, _T("这是一个Win32测试程序!"), -1, &rcText, DT_CENTER); EndPaint(hWnd, &ps); break; case WM_CREATE: if (!AllocConsole()) { MessageBox(hWnd, _T("创建控制台失败"), _T("初始化错误"), MB_OK); } SetConsoleTitle(_T("win32AllocConsoleTest")); // 这里重定向标准输出到控制台上 // 如果不做重定向就需要使用WriteConsole或者_cprintf函数 freopen( "CONOUT$", "w+t", stdout );// 申请写 //freopen( "CONIN$", "r+t", stdin ); // 申请读 std::wcout << _T("创建控制台并成功初始化") << std::endl; break; case WM_DESTROY: FreeConsole(); PostQuitMessage(0); break; default: return DefWindowProc(hWnd, message, wParam, lParam); } return 0; }
实例c 控制台字符属性详细用法介绍
函数SetConsoleTextAttribute可设置控制台显示的字符属性。支持一下设置:
Attribute | Meaning |
---|---|
FOREGROUND_BLUE | 前景色,包含蓝色 |
FOREGROUND_GREEN | 前景色,包含绿色 |
FOREGROUND_RED | 前景色,包含红色 |
FOREGROUND_INTENSITY | 前景色,加亮 |
BACKGROUND_BLUE | 背景色,包含蓝色 |
BACKGROUND_GREEN | 背景色,包含绿色 |
BACKGROUND_RED | 背景色,包含红色 |
BACKGROUND_INTENSITY | 背景色,加亮 |
COMMON_LVB_LEADING_BYTE | 多字节码的Leading byte. |
COMMON_LVB_TRAILING_BYTE | 多字节码的Trailing byte. |
COMMON_LVB_GRID_HORIZONTAL | 顶部水平网格(上划线) |
COMMON_LVB_GRID_LVERTICAL | 左竖直网格 |
COMMON_LVB_GRID_RVERTICAL | 右竖直网格 |
COMMON_LVB_REVERSE_VIDEO | 前景色背景色反转 |
COMMON_LVB_UNDERSCORE | 下划线 |
示例代码如下:
// 控制台字体属性设置示例 ChangeTextAttrDemo // 设置前景色、背景色、unicode下划线、删除线等 // 建议使用vs2005以上版本编译,unicode编码 #include <windows.h> #include <iostream> using std::wcout; using std::endl; int _tmain(int argc, _TCHAR* argv[]) { // 输出中文 std::wcout.imbue(std::locale("chs")); // 设置控制台标题栏 SetConsoleTitle(_T("ChangeTextAttrDemo")); HANDLE stdOutHandle = GetStdHandle(STD_OUTPUT_HANDLE); if (INVALID_HANDLE_VALUE == stdOutHandle) { wcout << L"调用GetStdHandle失败,错误码" << GetLastError() << endl; return 0; } // 默认背景色黑色,前景色白色 wcout << _T("默认背景色,ABCabc123*&@!") << endl << endl; // 红色前景色,绿色背景色 SetConsoleTextAttribute(stdOutHandle, FOREGROUND_RED|BACKGROUND_GREEN); wcout << _T("设置红色前景色,绿色背景色") << endl; wcout << _T("测试字符串,ABCabc123*&@!") << endl << endl; // 前景色加亮对比 SetConsoleTextAttribute(stdOutHandle, FOREGROUND_RED|BACKGROUND_GREEN|FOREGROUND_INTENSITY); wcout << _T("设置红色前景色,绿色背景色,前景色加亮对比") << endl; wcout << _T("测试字符串,ABCabc123*&@!") << endl << endl; // 设置为默认字体属性+上划线 SetConsoleTextAttribute(stdOutHandle, FOREGROUND_RED|FOREGROUND_BLUE|FOREGROUND_GREEN|COMMON_LVB_GRID_HORIZONTAL); wcout << _T("设置为默认字体属性+顶部水平网格") << endl; wcout << _T("测试字符串,ABCabc123*&@!") << endl << endl; // 设置为蓝色前景+下划线 SetConsoleTextAttribute(stdOutHandle, FOREGROUND_BLUE|COMMON_LVB_UNDERSCORE); wcout << _T("设置为蓝色前景+下划线") << endl; wcout << _T("测试字符串,ABCabc123*&@!") << endl << endl; // 设置为绿色前景+左划线 SetConsoleTextAttribute(stdOutHandle, FOREGROUND_GREEN|COMMON_LVB_GRID_LVERTICAL); wcout << _T("设置为绿色前景+左竖网格") << endl; wcout << _T(" 测试字符串,ABCabc123*&@!") << endl << endl; // 设置为绿色背景+右划线 SetConsoleTextAttribute(stdOutHandle, BACKGROUND_GREEN|COMMON_LVB_GRID_RVERTICAL); wcout << _T("设置为绿色背景+右竖网格") << endl; wcout << _T(" 测试字符串,ABCabc123*&@!") << endl << endl; SetConsoleTextAttribute(stdOutHandle, FOREGROUND_RED|FOREGROUND_BLUE|FOREGROUND_GREEN); return 0; }
如果需要彩色的控制台,建议关注下代码中的各种效果。上述宏可组合使用,支持8种前景色和背景色,输出效果如下图:
实例d 控制台光标位置、样式及位置
本实例介绍控制台下光标的样式获取及设置,光标位置的设置等。
代码如下。(具体效果需要自己编译代码查看)
// 控制台光标样式获取、设置,CursorAttrDemo // 1. 光标属性获取及设置 // 2. 光标位置获取及设置 // 建议使用vs2005以上版本编译,unicode编码 #include <windows.h> #include <iostream> using std::wcout; using std::endl; int _tmain(int argc, _TCHAR* argv[]) { // 输出中文 std::wcout.imbue(std::locale("chs")); // 设置控制台标题栏 SetConsoleTitle(_T("CursorAttrDemo")); HANDLE stdOutHandle = GetStdHandle(STD_OUTPUT_HANDLE); if (INVALID_HANDLE_VALUE == stdOutHandle) { wcout << L"调用GetStdHandle失败,错误码" << GetLastError() << endl; return 0; } CONSOLE_CURSOR_INFO cursor_info; memset(&cursor_info, 0, sizeof(cursor_info)); if (GetConsoleCursorInfo(stdOutHandle, &cursor_info)) { wcout << _T("光标可见:") << (cursor_info.bVisible ? _T("是") : _T("否")) << endl; wcout << _T("光标占位比例 :") << cursor_info.dwSize << _T("%") << endl; cursor_info.bVisible = TRUE; cursor_info.dwSize = 100; SetConsoleCursorInfo(stdOutHandle, &cursor_info); wcout << _T("设置100%光标占比") << endl; int x; std::cin >> x; cursor_info.dwSize = 50; SetConsoleCursorInfo(stdOutHandle, &cursor_info); wcout << _T("设置50%光标占比") << endl; } // 获取光标位置使用GetConsoleScreenBufferInfo函数 // 直接输出定位到第二行 COORD cursor_pos = {0, 8}; SetConsoleCursorPosition(stdOutHandle, cursor_pos); return 0; }
注:本文涉及所有代码可使用Git直接下载:https://git.oschina.net/Tocy/SampleCode.git。实际代码位于Console目录下,以1_开头的cpp文件。
本文作者:Tocy
版权所有,请勿用于商业用途,转载请注明原文地址。本人保留所有权利。
----------------------------------------------------------------------------------------------------------------------------
本文作者:Tocy e-mail: zyvj@qq.com
版权所有@2015-2020,请勿用于商业用途,转载请注明原文地址。本人保留所有权利。