控制台编程二
更新时间:2024-06-06 21:01:01 阅读量: 综合文库 文档下载
VC++控制台窗口界面的编程控制(二)
程序设计 2011-03-25 12:57:40 阅读9 评论0 字号:大中小 订阅
from
http://hi.http://www.wodefanwen.com//onlywater/blog/item/eb9a6dcf2c58eb38f9dc612f.html
2002-09-13 09:31 作者: 丁有和 出处: yesky 责任编辑: 七、滚动和移动
ScrollConsoleScreenBuffer是实现文本区滚动和移动的API函数。它可以将指定的一块文本区域移动到另一个区域,被移空的那块区域由指定字符填充。函数的原型如下:
BOOL ScrollConsoleScreenBuffer( HANDLE hConsoleOutput, // 句柄 CONST SMALL_RECT* lpScrollRectangle, // 要滚动或移动的区域 CONST SMALL_RECT* lpClipRectangle, // 裁剪区域 COORD dwDestinationOrigin, // 新的位置 CONST CHAR_INFO* lpFill // 填充字符 ); 利用这个API函数还可以实现删除指定行的操作。下面来举一个例子,程序如下: #include #include #include HANDLE hOut; void DeleteLine(int row); // 删除一行 void MoveText(int x, int y, SMALL_RECT rc); // 移动文本块区域 void ClearScreen(void); // 清屏 void main() { hOut = GetStdHandle(STD_OUTPUT_HANDLE); // 获取标准输出设备句柄 WORD att = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_INTENSITY | BACKGROUND_BLUE ; // 背景是蓝色,文本颜色是黄色 SetConsoleTextAttribute(hOut, att); ClearScreen();
printf(\ printf(\ printf(\ printf(\ CONSOLE_SCREEN_BUFFER_INFO bInfo;
GetConsoleScreenBufferInfo( hOut, &bInfo ); COORD endPos = {0, bInfo.dwSize.Y - 1};
SetConsoleCursorPosition(hOut, endPos); // 设置光标位置 SMALL_RECT rc = {0, 2, 40, 5}; _getch();
MoveText(10, 5, rc); _getch();
DeleteLine(5);
CloseHandle(hOut); // 关闭标准输出设备句柄 }
void DeleteLine(int row) {
SMALL_RECT rcScroll, rcClip; COORD crDest = {0, row - 1}; CHAR_INFO chFill;
CONSOLE_SCREEN_BUFFER_INFO bInfo;
GetConsoleScreenBufferInfo( hOut, &bInfo ); rcScroll.Left = 0; rcScroll.Top = row;
rcScroll.Right = bInfo.dwSize.X - 1; rcScroll.Bottom = bInfo.dwSize.Y - 1; rcClip = rcScroll;
chFill.Attributes = bInfo.wAttributes; chFill.Char.AsciiChar = ' ';
ScrollConsoleScreenBuffer(hOut, &rcScroll, &rcClip, crDest, &chFill); }
void MoveText(int x, int y, SMALL_RECT rc) {
COORD crDest = {x, y}; CHAR_INFO chFill;
CONSOLE_SCREEN_BUFFER_INFO bInfo;
GetConsoleScreenBufferInfo( hOut, &bInfo ); chFill.Attributes = bInfo.wAttributes; chFill.Char.AsciiChar = ' ';
ScrollConsoleScreenBuffer(hOut, &rc, NULL, crDest, &chFill); }
void ClearScreen(void) { CONSOLE_SCREEN_BUFFER_INFO bInfo; GetConsoleScreenBufferInfo( hOut, &bInfo ); COORD home = {0, 0}; WORD att = bInfo.wAttributes; unsigned long size = bInfo.dwSize.X * bInfo.dwSize.Y; FillConsoleOutputAttribute(hOut, att, size, home, NULL); FillConsoleOutputCharacter(hOut, ' ', size, home, NULL); } 程序中,实现删除行的操作DeleteLine的基本原理是:首先将裁剪区域和移动区域都设置成指定行row(包括该行)以下的控制台窗口区域,然后将移动的位置指定为(0, row-1)。这样,超出裁剪区域的内容被裁剪掉,从而达到删除行的目的。
需要说明的是,若裁剪区域参数为NULL,则裁剪区域为整个控制台窗口。
八、光标操作
控制台窗口中的光标反映了文本插入的当前位置,通过
SetConsoleCursorPosition函数可以改变这个“当前”位置,这样就能控制字符(串)输出。事实上,光标本身的大小和显示或隐藏也可以通过相应的API函数进行设定。例如:
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,光标最大,为一个字符大小的方块。
九、读取键盘信息
键盘事件通常有字符事件和按键事件,这些事件所附带的信息构成了键盘
信息。它是通过API函数ReadConsoleInput来获取的,其原型如下: BOOL ReadConsoleInput( HANDLE hConsoleInput, // 输入设备句柄 PINPUT_RECORD lpBuffer, // 返回数据记录 DWORD nLength, // 要读取的记录数 LPDWORD lpNumberOfEventsRead // 返回已读取的记录数 ); 其中,INPUT_RECORD定义如下: typedef struct _INPUT_RECORD { WORD EventType; // 事件类型 union { KEY_EVENT_RECORD KeyEvent; MOUSE_EVENT_RECORD MouseEvent; WINDOW_BUFFER_SIZE_RECORD WindowBufferSizeEvent; MENU_EVENT_RECORD MenuEvent; FOCUS_EVENT_RECORD FocusEvent; } Event; } INPUT_RECORD; 与键盘事件相关的记录结构KEY_EVENT_RECORD定义如下: typedef struct _KEY_EVENT_RECORD { BOOL bKeyDown; // TRUE表示键按下,FALSE表示键释放 WORD wRepeatCount; // 按键次数 WORD wVirtualKeyCode; // 虚拟键代码 WORD wVirtualScanCode; // 虚拟键扫描码 union { WCHAR UnicodeChar; // 宽字符 CHAR AsciiChar; // ASCII字符 } uChar; // 字符 DWORD dwControlKeyState; // 控制键状态 } KEY_EVENT_RECORD; 我们知道,键盘上每一个有意义的键都对应着一个唯一的扫描码,虽然扫描码可以作为键的标识,但它依赖于具体设备的。因此,在应用程序中,使用的往往是与具体设备无关的虚拟键代码。这种虚拟键代码是与设备无关的键盘编码。在Visual C++中,最常用的虚拟键代码已被定义在Winuser.h中,例如:VK_SHIFT表示SHIFT键,VK_F1表示功能键F1等。
上述结构定义中,dwControlKeyState用来表示控制键状态,它可以是CAPSLOCK_ON(CAPS LOCK灯亮)、ENHANCED_KEY(按下扩展键)、
LEFT_ALT_PRESSED(按下左ALT键)、LEFT_CTRL_PRESSED(按下左CTRL键)、NUMLOCK_ON (NUM LOCK灯亮)、RIGHT_ALT_PRESSED(按下右ALT键)、
RIGHT_CTRL_PRESSED(按下右CTRL键)、SCROLLLOCK_ON(SCROLL LOCK灯亮)和
SHIFT_PRESSED(按下SHIFT键)中的一个或多个值的组合。
下面的程序是将用户按键的字符输入到一个控制台窗口的某个区域中,并当按下NUM LOCK、CAPS LOCK和SCROLL LOCK键时,在控制台窗口的最后一行显示这些键的状态。 #include HANDLE hOut; HANDLE hIn;
void DrawBox(bool bSingle, SMALL_RECT rc); void ClearScreen(void);
void CharWindow(char ch, SMALL_RECT rc); // 将ch输入到指定的窗口中
void ControlStatus(DWORD state); // 在最后一行显示控制键的状态
void DeleteTopLine(SMALL_RECT rc); // 删除指定窗口中最上面的行并滚动 void main() {
hOut = GetStdHandle(STD_OUTPUT_HANDLE); // 获取标准输出设备句柄
hIn = GetStdHandle(STD_INPUT_HANDLE); // 获取标准输入设备句柄
WORD att = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_INTENSITY |
BACKGROUND_BLUE ; // 背景是蓝色,文本颜色是黄色
SetConsoleTextAttribute(hOut, att); ClearScreen(); // 清屏 INPUT_RECORD keyRec; DWORD state = 0, res; char ch;
SMALL_RECT rc = {20, 2, 40, 12}; DrawBox(true, rc);
COORD pos = {rc.Left+1, rc.Top+1};
SetConsoleCursorPosition(hOut, pos); // 设置光标位置 for(;;) // 循环 {
ReadConsoleInput(hIn, &keyRec, 1, &res);
if (state != keyRec.Event.KeyEvent.dwControlKeyState) { state = keyRec.Event.KeyEvent.dwControlKeyState; ControlStatus(state); }
if (keyRec.EventType == KEY_EVENT){
if (keyRec.Event.KeyEvent.wVirtualKeyCode == VK_ESCAPE)
break;
// 按ESC键退出循环
if (keyRec.Event.KeyEvent.bKeyDown) {
ch = keyRec.Event.KeyEvent.uChar.AsciiChar; CharWindow(ch, rc); } } }
pos.X = 0; pos.Y = 0;
SetConsoleCursorPosition(hOut, pos); // 设置光标位置 CloseHandle(hOut); // 关闭标准输出设备句柄 CloseHandle(hIn); // 关闭标准输入设备句柄 }
void CharWindow(char ch, SMALL_RECT rc) // 将ch输入到指定的窗口中 {
static COORD chPos = {rc.Left+1, rc.Top+1};
SetConsoleCursorPosition(hOut, chPos); // 设置光标位置 if ((ch<0x20)||(ch>0x7e)) return;
WriteConsoleOutputCharacter(hOut, &ch, 1, chPos, NULL); if (chPos.X>=(rc.Right-1)) {
chPos.X = rc.Left; chPos.Y++; }
if (chPos.Y>(rc.Bottom-1)) {
DeleteTopLine(rc);
chPos.Y = rc.Bottom-1; }
chPos.X++;
SetConsoleCursorPosition(hOut, chPos); // 设置光标位置 }
void ControlStatus(DWORD state) // 在最后一行显示控制键的状态 {
CONSOLE_SCREEN_BUFFER_INFO bInfo;
GetConsoleScreenBufferInfo( hOut, &bInfo ); COORD home = {0, bInfo.dwSize.Y-1}; WORD att0 = BACKGROUND_INTENSITY ;
WORD att1 = FOREGROUND_GREEN | FOREGROUND_INTENSITY | BACKGROUND_RED;
FillConsoleOutputAttribute(hOut, att0, bInfo.dwSize.X, home, NULL);
FillConsoleOutputCharacter(hOut, ' ', bInfo.dwSize.X, home, NULL);
SetConsoleTextAttribute(hOut, att1);
COORD staPos = {bInfo.dwSize.X-16,bInfo.dwSize.Y-1}; SetConsoleCursorPosition(hOut, staPos); if (state & NUMLOCK_ON)
WriteConsole(hOut, \ staPos.X += 4;
SetConsoleCursorPosition(hOut, staPos); if (state & CAPSLOCK_ON)
WriteConsole(hOut, \ staPos.X += 5;
SetConsoleCursorPosition(hOut, staPos); if (state & SCROLLLOCK_ON)
WriteConsole(hOut, \
SetConsoleTextAttribute(hOut, bInfo.wAttributes); // 恢复原来的属性
SetConsoleCursorPosition(hOut, bInfo.dwCursorPosition); // 恢复原来的光标位置 }
void DeleteTopLine(SMALL_RECT rc) {
COORD crDest;
CHAR_INFO chFill;
SMALL_RECT rcClip = rc;
rcClip.Left++; rcClip.Right--; rcClip.Top++; rcClip.Bottom--; crDest.X = rcClip.Left; crDest.Y = rcClip.Top - 1;
CONSOLE_SCREEN_BUFFER_INFO bInfo;
GetConsoleScreenBufferInfo( hOut, &bInfo ); chFill.Attributes = bInfo.wAttributes; chFill.Char.AsciiChar = ' ';
ScrollConsoleScreenBuffer(hOut, &rcClip, &rcClip, crDest, &chFill); }
程序运行结果如下图所示:
十、读取鼠标信息
与读取键盘信息方法相似,鼠标信息也是通过ReadConsoleInput来获取的,其MOUSE_EVENT_RECORD具有下列定义: typedef struct _MOUSE_EVENT_RECORD { COORD dwMousePosition; // 当前鼠标位置 DWORD dwButtonState; // 鼠标按钮状态 DWORD dwControlKeyState; // 键盘控制键状态 DWORD dwEventFlags; // 事件状态 } MOUSE_EVENT_RECORD; 其中,dwButtonState反映了用户按下鼠标按钮的情况,它可以是:FROM_LEFT_1ST_BUTTON_PRESSED(最左边按钮)、RIGHTMOST_BUTTON_PRESSED(最右边按钮)、FROM_LEFT_2ND_BUTTON_PRESSED(左起第二个按钮)、FROM_LEFT_3RD_BUTTON_PRESSED(左起第三个按钮)和
FROM_LEFT_4TH_BUTTON_PRESSED (左起第四个按钮)。而dwEventFlags表示鼠标的事件,如DOUBLE_CLICK(双击)、MOUSE_MOVED(移动)和MOUSE_WHEELED(滚轮滚动,只适用于Windows 2000/XP)。dwControlKeyState的含义同前。 下面举一个例子。这个例子能把鼠标的当前位置显示在控制台窗口的最后一行上,若单击鼠标左键,则在当前位置处写一个字符‘A’,若双击鼠标任一按钮,则程序终止。具体代码如下: #include <WINDOWS.H> #include <STDIO.H> #include <STRING.H> HANDLE hOut; HANDLE hIn; void ClearScreen(void); void DispMousePos(COORD pos); // 在最后一行显示鼠标位置 void main() { hOut = GetStdHandle(STD_OUTPUT_HANDLE); // 获取标准输出设备句柄 hIn = GetStdHandle(STD_INPUT_HANDLE); // 获取标准输入设备句柄
WORD att = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_INTENSITY |
BACKGROUND_BLUE ; // 背景是蓝色,文本颜色是黄色
SetConsoleTextAttribute(hOut, att); ClearScreen(); // 清屏 INPUT_RECORD mouseRec; DWORD state = 0, res; COORD pos = {0, 0}; for(;;) // 循环 {
ReadConsoleInput(hIn, &mouseRec, 1, &res); if (mouseRec.EventType == MOUSE_EVENT){
if (mouseRec.Event.MouseEvent.dwEventFlags == DOUBLE_CLICK) break;
// 双击鼠标退出循环
pos = mouseRec.Event.MouseEvent.dwMousePosition; DispMousePos(pos);
if (mouseRec.Event.MouseEvent.dwButtonState == FROM_LEFT_1ST_BUTTON_PRESSED)
FillConsoleOutputCharacter(hOut, 'A', 1, pos, NULL); } }
pos.X = 0; pos.Y = 0;
SetConsoleCursorPosition(hOut, pos); // 设置光标位置 CloseHandle(hOut); // 关闭标准输出设备句柄 CloseHandle(hIn); // 关闭标准输入设备句柄 }
void DispMousePos(COORD pos) // 在最后一行显示鼠标位置 {
CONSOLE_SCREEN_BUFFER_INFO bInfo;
GetConsoleScreenBufferInfo( hOut, &bInfo ); COORD home = {0, bInfo.dwSize.Y-1}; WORD att0 = BACKGROUND_INTENSITY ;
FillConsoleOutputAttribute(hOut, att0, bInfo.dwSize.X, home, NULL);
FillConsoleOutputCharacter(hOut, ' ', bInfo.dwSize.X, home, NULL);
char s[20];
sprintf(s,\
SetConsoleTextAttribute(hOut, att0); SetConsoleCursorPosition(hOut, home);
WriteConsole(hOut, s, strlen(s), NULL, NULL);
SetConsoleTextAttribute(hOut, bInfo.wAttributes); // 恢复原来的属性
SetConsoleCursorPosition(hOut, bInfo.dwCursorPosition); // 恢复原来的光标位置 }
void ClearScreen(void) {
CONSOLE_SCREEN_BUFFER_INFO bInfo;
GetConsoleScreenBufferInfo( hOut, &bInfo ); COORD home = {0, 0};
unsigned long size = bInfo.dwSize.X * bInfo.dwSize.Y; FillConsoleOutputAttribute(hOut, bInfo.wAttributes, size, home, NULL);
FillConsoleOutputCharacter(hOut, ' ', size, home, NULL); }
程序运行结果如下:
十一、结语
综上所述,利用控制台窗口的Widows API函数可以设计简洁美观的文本界面,使得用Visual C++ 6.0开发环境深入学习C
正在阅读:
控制台编程二06-06
3 厨房用品基本陈列原则08-29
2018-2019年初中英语宁夏初三中考模拟全真试卷含答案考点及解05-20
深入开展“党员安全责任区”、“党员身边无事故” 活动方案11-12
2014-2018年出租车计价器市场深度分析与投资前景预测11-26
债权部工作总结09-19
8Cr5MoV锻钢冷轧工作辊双频淬火工艺05-11
初中励志作文600字(精选5篇)03-31
生命密码计算方法精编版04-07
西方社会学理论复习资料 1docx09-09
- 多层物业服务方案
- (审判实务)习惯法与少数民族地区民间纠纷解决问题(孙 潋)
- 人教版新课标六年级下册语文全册教案
- 词语打卡
- photoshop实习报告
- 钢结构设计原理综合测试2
- 2014年期末练习题
- 高中数学中的逆向思维解题方法探讨
- 名师原创 全国通用2014-2015学年高二寒假作业 政治(一)Word版
- 北航《建筑结构检测鉴定与加固》在线作业三
- XX县卫生监督所工程建设项目可行性研究报告
- 小学四年级观察作文经典评语
- 浅谈110KV变电站电气一次设计-程泉焱(1)
- 安全员考试题库
- 国家电网公司变电运维管理规定(试行)
- 义务教育课程标准稿征求意见提纲
- 教学秘书面试技巧
- 钢结构工程施工组织设计
- 水利工程概论论文
- 09届九年级数学第四次模拟试卷
- 控制台
- 编程
- 流行病实习教材 (第二次修改) ok1
- 初三化学第1章复习讲义(勾伟)
- 大物实验理论题库及答案(我做过的精选的八套题_应付考试应该足够
- 中国南方电网有限责任公司电力安全工作规程(编)
- 领导扶贫慰问活动讲话稿(五篇)
- 信号微机监测系统(毕业论文doc)
- 通达信天天进金及选股指标公式-通达信公式-股旁网
- 尔雅世界建筑考试答案
- 十三五规划
- 电气试验工初、中、高职业资格标准
- 全自动洗衣机控制系统的设计
- 公司授权体系
- 放生乃大慈悲,有大功德 万物有灵-买虾蟹放生的奇妙一幕
- 巴罗宏观课后习题答案(2-18章)
- 小学四年级上册信息技术教学计划(贵州教育出版社)
- 中小学法制教育案例
- 质荧光棒量质量技术监督
- 修改病句专项练习
- 网站建设投标书详细模板
- C语言上机题库