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轴半径乘以纵横比)。
*/
已标记关键词 清除标记
©️2020 CSDN 皮肤主题: 编程工作室 设计师:CSDN官方博客 返回首页