1. 程式人生 > >windows API 畫正弦曲線,並新增一沿線走的動態圓

windows API 畫正弦曲線,並新增一沿線走的動態圓

今天呢,主要寫的是一個在視窗中畫一個正弦曲線。
然後呢,讓一個圓繞著這條曲線走起來,是一個動態的。
這裡呢,有一個很重要的函式就是 定時器 SetTimer函式。

下邊是一個關於這個函式的一些具體介紹(來自百度百科)

SetTimer函式的原型
UINT_PTR SetTimer(
HWND hWnd, // 視窗控制代碼
UINT_PTR nIDEvent, // 定時器ID,多個定時器時,可以通過該ID判斷是哪個定時器
UINT nElapse, // 時間間隔,單位為毫秒
TIMERPROC lpTimerFunc // 回撥函式
);
返回值:
型別:UINT_PTR
如果函式成功,hWnd引數為0,則返回新建立的時鐘編號,可以把這個時鐘編號傳遞給KillTimer來銷燬時鐘.
如果函式成功,hWnd引數為非0,則返回一個非零的整數,可以把這個非零的整數傳遞給KillTimer來銷燬時鐘.
如果函式失敗,返回值是零.若想獲得更多的錯誤資訊,呼叫GetLastError函式.
例如
SetTimer(m_hWnd,1,1000,NULL); //一個1秒觸發一次的定時器
在MFC程式中SetTimer被封裝在CWnd類中,呼叫就不用指定視窗控制代碼了
於是SetTimer函式的原型變為:
UINT SetTimer(UINT nIDEvent,UINT nElapse,void(CALLBACK EXPORT *lpfnTimer)(HWND,UINT ,YINT ,DWORD))
當使用SetTimer函式的時候,就會生成一個定時器,函式中nIDEvent指的是定時器的標識,也就是名字。
第三個引數是一個回撥函式,在這個函式裡,放入你想要做的事情的程式碼,你可以將它設定為NULL,也就是使用系統預設的回撥函式,系統預設的是OnTimer函式。

這個函式怎麼生成的呢?
你需要在需要計時器的類的生成OnTimer函式:在ClassWizard裡,選擇需要計時器的類,新增WM_TIMER訊息對映,就自動生成OnTimer函數了。
然後在函式裡新增程式碼,讓程式碼實現功能。每隔一段時間就會自動執行一次。
例:
SetTimer(NULL,1,1000,NULL);
NULL 預設是主程序呼叫
1:計時器的名稱;
1000:時間間隔,單位是毫秒;
NULL:使用OnTimer函式。
當不需要計時器的時候呼叫KillTimer(nIDEvent);
例如:KillTimer(1);

下邊就是具體程式碼:

/**************************************************************************************
 *  問題:在一個windows視窗中畫一個正弦曲線,有一個圓心在線上的圓動態繞線前進
 *  編輯者:李文順
 *  步驟:
 *      1、註冊視窗類 (RegisterClassEx)
 *      2、建立視窗      (CreateWindowsEx)
 *      3、在桌面顯示視窗   (ShowWindows)
 *      4、更新視窗客戶區   (UpdataWindows)
 *      5、進入無限迴圈的訊息獲取和處理的迴圈。
 *          GetMessage ,獲取訊息
 *          TranslateMessage ,轉換鍵盤訊息     
 *          DispatchMessage ,將訊息傳送到相應的視窗函式
 **************************************************************************************/
#include <windows.h> #include <math.h> #include <string.h> #define IDT_TIMER1 1 //定時器標識 #define SEGMENTS 500 //取點數(在一個週期內取500個點) #define PI 3.141215926 //圓周率 //函式申明 LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam); //全域性變數 char titleName[]="你隨意"
; //視窗標題 //圖形介面程式的入口 int APIENTRY WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nCmdShow) { //定義儲存視窗屬性的結構體,12個引數 WNDCLASSEX wcex; //設定視窗的屬性 wcex.cbSize = sizeof(WNDCLASSEX); wcex.style = CS_HREDRAW | CS_VREDRAW; //從這個視窗派生出的視窗具有的風格 wcex.lpfnWndProc = (WNDPROC)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 = titleName; //該視窗類的名稱 wcex.hIconSm = NULL; //小圖示控制代碼 //註冊視窗 ::RegisterClassEx(&wcex); HWND hWnd; //建立視窗 hWnd = ::CreateWindow(titleName, titleName, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL); if (!hWnd)return FALSE; //建立視窗失敗,返回 //顯示視窗 ::ShowWindow(hWnd, nCmdShow); //重新整理視窗客戶區 ::UpdateWindow(hWnd); //迴圈獲取\處理訊息 MSG msg; while(::GetMessage(&msg,0,0,0)) { ::TranslateMessage(&msg); //轉換鍵盤訊息 ::DispatchMessage(&msg); //將訊息傳送到相應的視窗函式 } return (int)msg.wParam; } //視窗訊息處理函式 LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { //全域性變數定義 static int index; static char sztest[56]; static s_cxClient,s_cyClient; static int rad; //視窗控制代碼定義 HDC hdc; RECT rect; PAINTSTRUCT ps; POINT pt[SEGMENTS]; int i; //找出500個座標點 for(i=0;i<SEGMENTS;i++) { pt[i].x = s_cxClient/4 + s_cxClient/2*i/SEGMENTS; pt[i].y = s_cyClient/4 + (int)((s_cyClient/4)*(1-sin(2*PI*i/SEGMENTS))); } switch(message) { case WM_CREATE: //視窗被建立時的訊息 //建立一個定時器,畫動態圓用 if(::SetTimer(hWnd,IDT_TIMER1,10,NULL)==0) { ::MessageBox(hWnd,"定時器安裝失敗!","03Timer",MB_OK); } return 0; case WM_SIZE: //每次視窗的大小被改變時的訊息 { ::GetClientRect(hWnd,&rect); //獲取視窗客戶區的大小 s_cxClient = rect.right - rect.left; s_cyClient = rect.bottom - rect.top; rad=s_cxClient/50; } return 0; case WM_TIMER: //定時器時間到訊息 { hdc=GetDC(hWnd); if(::IsIconic(hWnd))return 0; //文字資訊顯示 wsprintf(sztest,"測試:%d rad: %d",index,rad); ::TextOut(hdc,10,10,sztest,strlen(sztest)); //畫筆設定 HPEN hPenWhite = (HPEN)::CreatePen(PS_SOLID,2,RGB(250,250,250)); //自定義白色線 HPEN hPenBlue = (HPEN)::CreatePen(PS_SOLID,2,RGB(0,0,250)); //自定義藍色線 HPEN hPenBlack = (HPEN)::GetStockObject(BLACK_PEN); //預定義黑色線 //消除上次圓圈痕跡 HPEN hOldPen3 = (HPEN)::SelectObject(hdc,hPenWhite); ::Ellipse(hdc,pt[index].x-rad,pt[index].y-rad,pt[index].x+rad,pt[index].y+rad); if(index==SEGMENTS)index=0; else index++; //畫圓 HPEN hOldPen1 = (HPEN)::SelectObject(hdc,hPenBlue); ::Ellipse(hdc,pt[index].x-rad,pt[index].y-rad,pt[index].x+rad,pt[index].y+rad); //畫正弦波 HPEN hOldPen2 = (HPEN)::SelectObject(hdc,hPenBlack); ::Polyline(hdc,pt,SEGMENTS); } return 0; case WM_PAINT: hdc = ::BeginPaint(hWnd,&ps); //使無效的客戶區變得有效,並取得環境裝置 //畫正弦曲線 ::Polyline(hdc,pt,SEGMENTS); ::EndPaint(hWnd,&ps); //釋放環境變數控制代碼,和::BeginPaint 配套使用 break; case WM_CLOSE: { ::KillTimer(hWnd,IDT_TIMER1); ::DestroyWindow(hWnd); } return 0; case WM_DESTROY: ::PostQuitMessage(0); //該函式向訊息佇列中插入一條 WM_QUIT 訊息,由 GetMessage 函式捕獲返回 0 而退出程式 break; } return ::DefWindowProc(hWnd,message,wParam,lParam); } /* Ellipse()畫橢圓弧函式 功能: 函式ellipse()使用當前繪圖色畫一橢圓弧。 用法: 該函式呼叫方式為void ellipse(int x,int y,int startangle,int endangle,int xradius,int yradius); 說明: 引數x,y為橢圓中心座標,startangle和endangle為給定的起始角和終止角,xradius與yradius為橢圓的x軸半徑 與y軸半徑,如果startangle為0 ,endangle等於360度,那麼畫出的是個完整的橢圓。 ellipse()函式不同於arc()和circle()函式,屏顯縱橫比不能自動調節。 若需要的是成比例的半徑而不是特定的畫素距離,則y軸距離必須調節為yradius*aspectratio(y軸半徑乘以縱橫比)。 */