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軸半徑乘以縱橫比)。
*/
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章