Windows控制檯下繪製簡單圖形


最近接觸到一個很有意思的問題,如何在Windows控制檯下畫圖,翻遍了C的頭文件也沒找到畫圖的函數,好吧,那就用Windows提供的API函數吧,看來想移植是沒戲了。先畫一個簡單的圖,類似心電圖那種吧,假設得到的數據是縱座標的值,橫座標默認從0開始,每隔512uS(微秒的那個符號不會打)得到一個縱座標值,要求將所有縱座標值連起來,就以這個簡單的程序爲例吧。

  既然有了需求,實現起來就簡單了,首先我們應該有一個控制檯窗口的上下文(device context)句柄,然後使用MoveToExLineTo函數連線就行了。代碼如下:

  

複製代碼
#include <windows.h> #include <stdio.h> #include <conio.h> #include "data.h"  //聲明瞭名爲point的二維數組,以及記錄數組元素個數的NUMBER常量 // //下列X-Y座標平面的值取決於控制檯的尺寸,需要根據實際情況進行調整 // //起始X座標 #define X_START 10 //結束X座標 #define X_END 650 //每個值的X座標增量,相當於512uS #define X_INC 10 //Y座標 #define Y 250 int main() { HWND hwnd; HDC hdc; int i; //獲取console的設備上下文句柄 hwnd = GetConsoleWindow(); hdc = GetDC(hwnd); //調整一下console背景顏色,否則看不清線條 system("color 3D"); //起始位置,Windows中窗口的座標系相當於直角座標系第一象限翻轉到第四象限 MoveToEx(hdc,X_START,Y,NULL); //畫基準座標線 LineTo(hdc,X_END,Y); //開始繪圖 MoveToEx(hdc,X_START,Y,NULL); for (i = 0; i < NUMBER; i++) { LineTo(hdc,point[i].x,point[i].y); } _getch(); return 0; }
複製代碼

  但是這個程序存在一個問題,就是如果控制檯被其它窗口遮住後,已經繪製的線條不會重繪,也就意味着那部分線條看不見了,只能重新運行程序,這個問題怎麼解決呢?我也不知道,不過可以將整個函數包含一個while循環裏,如果自己是頂層窗口就重新繪製,只是這樣似乎代價太大了,呵呵。

  來看一下這個程序繪製的圖形吧。

  line

  既然能繪製出線條自然就可以會繪製出柱形圖之類的圖形,稍微修改一下就可以了,代碼就不貼了,效果如下圖。

  photo

  上面這些都比較好畫,那麼如果畫圓呢?

  我想到兩種方法,第一種方法是計算,首先分別計算出最大和最小的X、Y值(xmin,xmax,ymin,ymax),然後根據X^2+Y^2=R^2,在for (x = xmin; x <= xmax; x++)內部計算Y值,最後畫點就是了;這個應該是比較簡單的。

  第二種方法是掃描,左上角(xmin,ymin)、右上角(xmax,ymin)、左下角(xmin,ymax)和右下角(xmax,ymax)這四個點確定一個正方形,對正方形內部對每個點進行運算,也是根據X^2+Y^2=R2,只是現在根據X和Y算出R0,然後跟R對比而已,而且比第一種方法多了一個判斷——是否到達行末,若到達行末則跳到下一行,若已經到了最後一行的最後一列,那就跳出循環。不過這個方法顯然比較奢侈,如果半徑增大n倍的話,計算量增大了n^2倍。就貼這種方法的代碼吧。

  

複製代碼
void circle(POINT *center,int radius) { HWND hwnd; HDC hdc; int xmin = center->x - radius; int xmax = center->x + radius; int ymin = center->y - radius; int ymax = center->y + radius; POINT point; hwnd = GetConsoleWindow(); hdc = GetDC(hwnd); point.x = xmin; point.y = ymin; MoveToEx(hdc,center->x,center->y - radius,NULL); while (TRUE) { if (fabs(sqrt(pow2(point.x - center->x) + pow2(point.y - center->y)) - radius) <= 1) { DrawPoint(hdc,&point); } //是否到達行末 if (point.x == xmax) { if (point.y == ymax) { break; } else { point.x = xmin; point.y++; continue; } } point.x++; } }
複製代碼

  繪製的圓如下圖:

  circle

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章