windows API 畫正弦曲線,並新增一沿線走的動態圓
阿新 • • 發佈:2019-01-10
今天呢,主要寫的是一個在視窗中畫一個正弦曲線。
然後呢,讓一個圓繞著這條曲線走起來,是一個動態的。
這裡呢,有一個很重要的函式就是 定時器 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軸半徑乘以縱橫比)。
*/