這問題實在看了很多人問,但大多是視窗程式還沒學過,只學到 Console 下之程式設計便問要怎麼畫波形圖。在 Console 下畫不是不能畫,可以說是「不習慣」,也可以說是「不好畫」。
這問題我用四種不同方法解過 -
(1) 直接用 Console Mode 上用 printf / cout 去畫,但這個很麻煩
(2) 調用 Console Function 在 Console Window 上畫
(3) 用 Win32 API 去畫
(4) 用 MFC 去畫
上述方法扣除掉第一項不予置評 (那畫出來實在是太醜了),Console Window 畫實在覺得沒必要,MFC 算久沒再碰了,這裡只用 Win32 慢慢刻。程式碼沒寫得很好,改善空間甚大。
#pragma comment(lib, "Winmm.lib") /* using API - PlaySound */ #include <windows.h> #include <math.h> // ============================================= // 繪圖函式 視窗位置與大小 #define WINDOW_X0 0 #define WINDOW_Y0 0 #define HEIGHT 300 #define WIDTH 400 // ============================================= // 繪圖相關資訊 #define RATE (10.0) /* 縮放比例*/ #define X0 WIDTH/2 #define Y0 HEIGHT/2 #define Xd (1E-2) #define START_X (-50.0) // ============================================= // 自定義 MyPoint struct,雖已有 struct POINT,但 POINT::X POINT::Y 為整數 typedef struct MyPointtag{ double x; double y; }MyPoint; // ============================================= // 資料量 #define N 10000 MyPoint *pt; /* 紀錄之資料點, 方便設成全域變數*/ // ============================================= // function declare LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); /* 宣告訊息處理函式 */ void PaintGraphic(HWND ); /* 繪圖函式 */ void SaveAsBmp(HWND); /* ��成bmp */ // ============================================= // 取得輸入資料 , 以 y = sin(x) * x^1/3 , x=START_X step 0.05 產生 void GetInput(unsigned cnt) { unsigned i=0; for(; i!=cnt; ++i){ pt[i].x = START_X + i*Xd; pt[i].y = sqrt(abs(pt[i].x))*sin(pt[i].x); } } // ============================================= // 繪圖函式 void PaintGraphic(HWND hwnd) { HDC hdc; PAINTSTRUCT ps; unsigned i; HPEN hPen,hOldPen; InvalidateRect(hwnd, NULL, TRUE); hdc = BeginPaint(hwnd, &ps); /*建立畫筆*/ hPen=CreatePen(PS_SOLID,2,0x00ff00); hOldPen=(HPEN)SelectObject(hdc,hPen); /*繪出 x 基準線*/ MoveToEx(hdc, 0, HEIGHT-Y0, NULL); LineTo(hdc, WIDTH, HEIGHT-Y0); /*繪出 Y 基準線*/ MoveToEx(hdc, X0, 0, NULL); LineTo(hdc, X0, HEIGHT); /*重建立另一色畫筆*/ DeleteObject(hPen); hPen=CreatePen(PS_SOLID,2,0xff00ff); hOldPen=(HPEN)SelectObject(hdc,hPen); for(i=1; i!=N; ++i){ MoveToEx(hdc, (pt[i-1].x)*RATE+X0, HEIGHT - (pt[i-1].y)*RATE - Y0,NULL); LineTo(hdc, (pt[i].x)*RATE+X0, HEIGHT - (pt[i].y)*RATE - Y0); } DeleteObject(hPen); EndPaint(hwnd, &ps); } // ============================================= // 繪圖函式 WinMain 函式, 相當於 Console 之 main int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow) { static TCHAR szAppName[] = TEXT("function graphic - vc2008 (by EdisonX, EdisonShih)"); HWND hwnd; MSG msg; WNDCLASS WndClass; /* 配置 N 個資料點 , 並讀入 */ pt = (MyPoint*)malloc(sizeof(MyPoint)*N); GetInput(N); WndClass.style = CS_HREDRAW | CS_VREDRAW; /* 視窗大小改變時重繪 */ WndClass.lpfnWndProc = WndProc; /* 設定此視窗處理之訊息函式, lpfnWndProc 實為函式指標 */ WndClass.cbClsExtra = 0; /* 通常設0 */ WndClass.cbWndExtra = 0; /* 通常設0 */ WndClass.hInstance = hInstance; WndClass.hIcon = LoadIcon(NULL, IDI_APPLICATION); /* 應用程式 Icon */ WndClass.hCursor = LoadCursor(NULL, IDC_ARROW); /* 滑鼠游標 */ WndClass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); /* 背景色 */ WndClass.lpszMenuName = NULL; /* 不設選單(菜單,Menu) */ WndClass.lpszClassName = szAppName; /* 應用程式名稱 */ /* 註冊已填好結構之視窗, 若失敗則跳出 */ if(!RegisterClass(&WndClass)){ MessageBox(NULL, TEXT("RegisterClass Window Fail."),szAppName, MB_ICONERROR); return EXIT_FAILURE; } /* 建立視窗 */ hwnd = CreateWindow(szAppName, TEXT("Window Title"), // WS_CAPTION | WS_SYSMENU, /* 通常��用 WS_OVERLAPPEDWINDOW, 但此處不允許改變視窗大小 */ WS_POPUPWINDOW, /* 由於要做截圖,故不繪制外框,截下來就只有圖形 */ WINDOW_X0,WINDOW_Y0,WIDTH,HEIGHT, /* 使用預設 : CW_USEDEFAULT */ NULL,NULL,hInstance,NULL); ShowWindow(hwnd, SW_SHOW); /* 顯示此視窗 */ UpdateWindow(hwnd); /* 直接先更新一次 */ /* 進入訊息回圈 */ while( GetMessage(&msg, NULL, 0, 0)){ /* 取得訊息 */ TranslateMessage(&msg); /* 翻譯 */ DispatchMessage(&msg); /* 分配 */ } return msg.wParam; } // ============================================= // 自定義之 WndProc 訊息處理函式 LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { /* 針對截取之訊息做處理 */ switch(message) { case WM_RBUTTONDOWN : /* 右鍵時也將進行視窗銷毀 */ case WM_DESTROY: /* 視窗銷毀 */ PostQuitMessage(0); return 0; case WM_PAINT: /* 重繪 */ PaintGraphic(hwnd ); return 0; case WM_LBUTTONDOWN: /* 按下滑鼠左鍵時自動��成 bmp */ SaveAsBmp(hwnd); return 0; } /* 其��未處理之訊息以預設方式處理 */ return DefWindowProc(hwnd, message, wParam, lParam); } // ============================================= // ��成bmp void SaveAsBmp(HWND hwnd) { static int number=0; char filename[MAX_PATH]; HDC hdcWindow; HDC hdcMemory; HBITMAP hBitmap; BYTE *lpvBits; BITMAPINFO bi; BITMAPINFOHEADER bih; BITMAPFILEHEADER bifh; HANDLE hFile; DWORD dwBytesWritten = 0; DWORD dwSize; int xSize, ySize; RECT rect; sprintf(filename, "%d.bmp", ++number); hdcWindow = GetDC(NULL); GetWindowRect(hwnd, &rect); xSize = rect.right - rect.left; ySize = rect.bottom - rect.top; hBitmap = CreateCompatibleBitmap(hdcWindow, xSize, ySize); hdcMemory = CreateCompatibleDC(hdcWindow); SelectObject(hdcMemory, hBitmap); BitBlt(hdcMemory, 0, 0, xSize, ySize, hdcWindow, rect.left, rect.top, SRCCOPY); bih.biSize = sizeof(BITMAPINFOHEADER); bih.biWidth = xSize; bih.biHeight = ySize; bih.biPlanes = 1; bih.biBitCount = 32; bih.biCompression = BI_RGB; bih.biSizeImage = 0; bih.biXPelsPerMeter = 0; bih.biYPelsPerMeter = 0; bih.biClrUsed = 0; bih.biClrImportant = 0; dwSize = (((xSize * 32 + 31)/32) * 4 * ySize); lpvBits = (BYTE*)malloc(dwSize); bifh.bfType = 0x4D42; bifh.bfSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + dwSize; bifh.bfOffBits = (DWORD)sizeof(BITMAPFILEHEADER) + (DWORD)sizeof(BITMAPINFOHEADER); bifh.bfReserved1 = 0; bifh.bfReserved2 = 0; bi.bmiHeader = bih; GetDIBits(hdcMemory, hBitmap, 0, (UINT)ySize, lpvBits, &bi, DIB_RGB_COLORS); hFile = CreateFile(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); WriteFile(hFile, (LPSTR)&bifh, sizeof(BITMAPFILEHEADER), &dwBytesWritten, NULL); WriteFile(hFile, (LPSTR)&bih, sizeof(BITMAPINFOHEADER), &dwBytesWritten, NULL); WriteFile(hFile, (LPSTR)lpvBits, dwSize, &dwBytesWritten, NULL); DeleteDC(hdcMemory); DeleteObject(hBitmap); CloseHandle(hFile); free(lpvBits); ReleaseDC(hwnd, hdcWindow); /*完成後提示音效*/ PlaySound(TEXT("Asterisk"), NULL, SND_ALIAS); }執行結果圖
全站熱搜
留言列表