前面快乐高四第三十三课,介绍了在控制台程序中怎么利用CChart绘制曲线,那里的方法呢,很简单,就是创建一个弹出窗口,然后在这个弹出窗口上绘图,其实技术含量比较低。

这一课呢,笨笨想给大家介绍一下怎么直接在控制台窗口上绘图。什么,是那个黑不拉几的Dos窗口吗?听到这个想法,你是不是想吐血啊?哈哈!!!!!

在控制台窗口绘图,最困难的是Win32窗口中我们认为理所当然的东西,里面居然没有,比如各种消息!

下面还是开始吧,让我们回到旧石器时代。

第一步,建立一个控制台程序,注意选择“A simple application”,这样IDE会帮忙建立一个空的程序,省一点事。

第二步,引入CChart,并加入要用的头文件。

#include "Chart.h"
#if defined(_UNICODE) || defined(UNICODE)
#   pragma comment(lib,"CChartu.lib")
#else
#   pragma comment(lib,"CChart.lib")
#endif
using namespace NsCChart;#include <windows.h>
#include <stdio.h>
#include <conio.h>
#include <math.h>#define WM_MOUSEWHEEL 0x020Aextern "C" WINBASEAPI HWND WINAPI GetConsoleWindow();

这里引入了Windows的一个未公开的API,GetConsoleWindow(),用于找到程序的控制台窗口句柄。也可用FindWindow这个API,但比较麻烦。

第三步,添加两个全局变量。

CChart chart;
HWND hWnd;

这里chart用来绘图,不需多说,hWnd用于保存控制台窗口句柄。

第四步,编写绘图子函数。

// 绘图函数
void    MyDraw()
{HDC hDC = GetDC(hWnd);RECT rt;GetClientRect(hWnd, &rt);rt.top = (rt.top+rt.bottom)/2;chart.OnDraw(hDC, rt);ReleaseDC(hWnd, hDC);
}

这个套路大家应该都很熟悉,注意这里我们想利用控制台窗口的下半拉画图。

有了全局的HWND句柄,利用GetDC获得HDC,在HDC上绘图。最后必须释放HDC,不然内存会泄露。

第五步,在main()函数的一开始,就初始化hWnd。

hWnd = GetConsoleWindow();

这里就是利用了那个未公开的API获得控制台窗口句柄。

第六步,设置CChart数据。

    double pi = 4.0*atan(1.0);int perioid = 360;for(int i=0; i<4*perioid; ++i){chart.AddPoint2D(i, 1.4*sin(i*2.0*pi/perioid));}chart.SetTitle(_T("在控制台窗口中绘图"));

当然这里随便怎么添加数据都可以的。

第七步,绘图。在上面的代码后面添加:

    MyDraw();printf("控制台窗口绘图!\n");

这里简单调用了前面编写的绘图子函数。由于我们是在窗口下半拉绘图,上半拉仍然可以用于控制台的字符输出,所以这里测试了一下printf输出函数。

效果如图呢!

怎么样?还是不错吧!

第八步,调整一下样式。

这里CChart默认是白背景,控制台窗口是黑背景,有点不协调。那我们添加下面两句话调整一下。

    chart.SetBkgndColor(RGB(0, 0, 0));chart.SetTitleColor(RGB(245, 245, 245));

现在的效果如图。

这下融为一体了。

第九步,添加消息循环,并增加重绘功能。

从输出图像可以看到Press any key to continue字样,老鸟都知道这表示程序已经结束。

另外我们如果把这个控制台窗口隐藏一下再打开,图像就消失了。这不符合我们的需要。

在上面的代码后面添加如下代码。

    HANDLE hIn = GetStdHandle(STD_INPUT_HANDLE);HANDLE Hout = GetStdHandle(STD_OUTPUT_HANDLE);INPUT_RECORD inp;DWORD recnum;bool loop = true;while(loop){ReadConsoleInput(hIn, &inp, 1, &recnum);switch(inp.EventType){case FOCUS_EVENT:MyDraw();break;}}CloseHandle(hIn);CloseHandle(Hout);

效果如图。

上面加了一个死循环处理消息。和普通的Windows消息循环不一样,这里用ReadConsoleInput读取消息,在窗口焦点事件FOCUS_EVENT中重绘。

这下解决了上面的问题。注意字符光标在闪烁,表明程序在运行中,并没有结束。

第十步,添加死循环退出机制。

上面的死循环无法退出。虽然Ctrl+C可以退出程序,但这样会影响资源的释放。

添加代码。

        case KEY_EVENT:if(inp.Event.KeyEvent.uChar.AsciiChar=='c' || inp.Event.KeyEvent.uChar.AsciiChar=='C')loop = false;break;

这下按c键就可以退出了。注意和Ctrl+C的区别,c键只是退出循环,控制台窗口还在,Ctrl+C是连控制台窗口也关闭了。

第十一步,添加鼠标处理消息。

在死循环前加两个用于消息处理的变量。

    POINT point;UINT message;

添加消息处理代码。

        case MOUSE_EVENT:if(inp.Event.MouseEvent.dwEventFlags == 0)//单击(包括按下或释放){if(inp.Event.MouseEvent.dwButtonState == FROM_LEFT_1ST_BUTTON_PRESSED)//左键按下{message = WM_LBUTTONDOWN;}else if(inp.Event.MouseEvent.dwButtonState == RIGHTMOST_BUTTON_PRESSED)//右键按下{message = WM_CONTEXTMENU;}else if(inp.Event.MouseEvent.dwButtonState == FROM_LEFT_2ND_BUTTON_PRESSED)//滚轮{message = WM_MOUSEWHEEL;}//释放的时候:else if(inp.Event.MouseEvent.dwButtonState == 0){message = WM_LBUTTONUP;}}else if(inp.Event.MouseEvent.dwEventFlags == DOUBLE_CLICK)//双击{message = WM_LBUTTONDBLCLK;}else if(inp.Event.MouseEvent.dwEventFlags == MOUSE_MOVED)//移动{message = WM_MOUSEMOVE;}else{message = WM_MOUSEMOVE;}GetCursorPos(&point);ScreenToClient(hWnd, &point);if(chart.OnEvent(hWnd, message, inp.Event.MouseEvent.dwControlKeyState, point.x + (point.y<<16))) MyDraw();break;

可以看到,这里先把保存在INPUT_RECORD变量中的鼠标事件信息转换为Windows的常规鼠标消息,然后调用CChart的消息处理函数OnEvent来处理消息。另外,INPUT_RECORD变量中并没有保存鼠标的像素位置信息,只有字符输入的行列信息,这里直接读取鼠标的屏幕坐标并转换为控制台窗口的客户区坐标,而鼠标消息的LPARAM变量低16位为客户区X坐标,高十六位为客户区Y坐标,采用移位的方式point.x + (point.y<<16)把point转换为LPARAM。

运行效果如图。

鼠标的各种消息,除了右键菜单外,都可以正常处理。控制台的右键菜单暂时还不知道怎么调出来。

各种对话框窗口也没有问题。

今天的旧石器时代之旅就告一段落了。

深入浅出CChart 每日一课——快乐高四第四十九课 旧石器时代,老血狂喷之控制台窗口绘图相关推荐

  1. 深入浅出CChart 每日一课——快乐高四第五十六课 絮絮叨叨,岁月杀猪刀之FAQ

    CChart发布已有多年,QQ交流群也成立了很久.在和网友的交流中,发行了CChart的很多问题,也进行了很多改进和完善. 网友们接触CChart的时间有早有晚,不同的网友经常在群里或私聊的时候提出的 ...

  2. 深入浅出CChart 每日一课——快乐高四第五十七课 新的起点,炫彩界面库之老树新芽

    CChart对多种DirectUI库具有良好的适配性,炫彩界面库也不例外.前面已经有两篇关于炫彩界面库的课程,分别是第17课"深入浅出CChart 每日一课--第十七课 时尚加潮流,Dire ...

  3. NeHe OpenGL第十九课:粒子系统

    NeHe OpenGL第十九课:粒子系统 粒子系统: 你是否希望创建爆炸,喷泉,流星之类的效果.这一课将告诉你如何创建一个简单的例子系统,并用它来创建一种喷射的效果. 欢迎来到第十九课.你已经学习了很 ...

  4. NeHe OpenGL第二十九课:Blt函数

    NeHe OpenGL第二十九课:Blt函数 Blitter 函数: 类似于DirectDraw的blit函数,过时的技术,我们有实现了它.它非常的简单,就是把一块纹理贴到另一块纹理上. 这篇文章是有 ...

  5. NeHe OpenGL教程 第二十九课:Blt函数

    转自[翻译]NeHe OpenGL 教程 前言 声明,此 NeHe OpenGL教程系列文章由51博客yarin翻译(2010-08-19),本博客为转载并稍加整理与修改.对NeHe的OpenGL管线 ...

  6. python第二十九课——文件读写(复制文件)

    自定义函数:实现文件复制操作有形参(2个) 没有返回值相似版(不用) def copyFile(src,dest):#1.打开两个文件:1个关联读操作,1个关联写操作fr=open(src,'rb') ...

  7. NeHe OpenGL第三十九课:物理模拟

    NeHe OpenGL第三十九课:物理模拟 物理模拟简介: 还记得高中的物理吧,直线运动,自由落体运动,弹簧.在这一课里,我们将创造这一切.   物理模拟介绍 如果你很熟悉物理规律,并且想实现它,这篇 ...

  8. Python-opencv学习第二十九课:高斯双边模糊

    Python-opencv学习第二十九课:高斯双边模糊 文章目录 Python-opencv学习第二十九课:高斯双边模糊 一.学习部分 二.代码部分 1.引入库 2.读入数据 3.完整代码 三.运行结 ...

  9. C语言笔记 第三十九课 程序中的三国天下

    第三十九课 程序中的三国天下 程序中的栈 栈是现代计算机程序里最为重要的概念之一 栈在程序中用于维护函数调用上下文 函数中的参数和局部变量存储在栈上 栈是一种行为,一种先进后出的行为 栈保存了一个函数 ...

最新文章

  1. “WPF老矣,尚能饭否”—且说说WPF今生未来(上):担心
  2. UVA 10129 Play on Words(欧拉道路)
  3. 终极之战!TensorFlow与PyTorch谁最适合深度学习
  4. DBGrid内使用CheckBox功能
  5. java 泛型 擦除_Java泛型和类型擦除
  6. c语言规定学号长度,c语言第1-9章基本概念练习题ans(最全).docx
  7. Uploadify插件上传图片并且插入到FCKeditor
  8. MFC无界面后台运行程序
  9. 图片php木马制作教程,图片木马制作大法
  10. android 命令pm 全称 packagemanager,Android.content.pm.PackageManager--(转载)
  11. CPU飙高系统反应慢怎么排查?
  12. 一文学会Maven私服的搭建
  13. 苹果x微信为什么不出定位服务器,苹果x微信发动态为什么显示不了位置
  14. EHub_tx1_tx2_E100 测试VisionWorks跑自带的demo
  15. 从跨境电商方向选择谈起
  16. 故障网络连接故障排除,第2部分:基本网络命令
  17. C语言:有一个一维数组score,内放10个学生成绩,求平均成绩。
  18. win11安装低版本CAD报致命错误解决方案
  19. 5.8G传输设备替代方案(解决5.8G设备的抗干扰问题)5.8G点对点 点对多点无线网络
  20. 云炬股市学习笔记20220118

热门文章

  1. 微信公众号获取jsapi_ticket(多类型)
  2. i春秋之荒岛求生write-up
  3. 利用mklink命令备份IE收藏夹
  4. 2021年电工(高级)考试题及电工(高级)新版试题
  5. 流量卡之家:共享建设5G 电信联通可以少花多少钱
  6. 为什么从上家公司离职的原因
  7. 基于澳大利亚气象数据集可视化分析及降雨预测
  8. 计算机的数据层 应用层,会话层,表示层,应用层
  9. 【机会】蘑菇街招聘DBA
  10. 下载软件 (三) openocd-windows