【C++源码】基于Win32窗口编程实现的小动画

来源:互联网 发布:java条件查询数据库 编辑:程序博客网 时间:2024/06/07 05:33

            翻开3年前刚接触计算机编程时作为练习写下的小动画源码,仿佛又回去那段充满乐趣的学习阶段,那时每当写完一个小程序都会有一种发自内心的自豪,都会有问自己离真正的程序员是不是已经很近了?回首阅读这些代码,不由感慨如今的我仅是如此严谨,已经没了往日的放荡不羁!那时总是在随心所欲中达到既定的目标,虽然也有着写一手优美代码的愿望,可年幼无知基本不知道什么才是优美,以至于代码是如此的“野”,太多的变量没初始化,太多的不安全函数,以及成块成块的宏定义。

          而现在为公司写代码,已容不得半丝放荡的风格,每一行都得斟酌再三,除了逻辑外还要吻合编码规范。 有时真不想如此这样小心翼翼,但却又明白对于程序员来讲一个程序的可靠性是至高无上的,自己还没有达到无规则成方圆的境界,更不敢出此诳语。

 

#include "windows.h"#include "math.h"#define COL_RED (RGB(255,0,0))#define COL_WHITE (RGB(255,255,255))#define COL_BLUE (RGB(0,0,255))#define COL_GREEN (RGB(0,255,0))#define COL_BLACK (RGB(0,0,0))#define BALLNUMBER 30// 被操作的球数目#define PI3.1415926// pi定义#define AngToRad(x)(((float)(x))/180*PI)// 角度制转化为弧度制#define RadToAng(x) (double(x)/PI*180)    // 弧度制转化为角度制#define DISTANCE(pt1,pt2) sqrt((float)(pt1.x-pt2.x)*(pt1.x-pt2.x)+(pt1.y-pt2.y)*(pt1.y-pt2.y))   // 计算两点之间的距离 // 定义球类ball#ifndef __BALL#define __BALLclass ball{private:POINT pos;// 圆心位置unsigned int r;// 半径长度COLORREF col;// 颜色int id;// 唯一标识此球public:ball();BOOL init(POINT pos,unsigned int r, COLORREF col);// 对象初始化// 基本属性操作函数POINT SetPos(POINT newPos);// 设置新位置为newPos,返回oldPos;POINT GetPos();// 返回pos;unsigned int SetR(unsigned int newR);// 设置新半径,返回旧半径unsigned int GetR();// 返回半径RCOLORREF SetCol(COLORREF newCol);// 设置新颜色,返回旧颜色COLORREF GetCol();// 返回颜色colvoid SetId(int id);int GetId();// 行为表现函数BOOL draw(HDC hdc,COLORREF col,bool isErase);// 将此球用hdc画出};#endif//定义新类型操作一些球以达到动画的效果/****************************坐标系如下****************************1、x轴正方向——右2、y轴正方向——下3、角度正方向——顺时针*/#ifndef __HANDLE_BALL#define __HANDLE_BALLclass HandleBall{private:ball *pBalls[BALLNUMBER];// 指向球类的指针数组int BallAngles[BALLNUMBER];// 对应球移动的偏移角度HWND hWnd;// 窗口句柄int MoveLen;// 球移动的位移量int ball_r;// 各球的半径//私有函数定义int Reflect(int aSrc,int aRef);// 返回aSrc方向按照aRef方向反射之后的方向 void MoveOneBall(ball* pBall,int Angle,int len);// 按照给定的角度Angle,给定的位移len移动给定的球pBall;bool isHitWall(ball* pBall,int bdAngle,int len,RECT rt,int *Angle,POINT *Pos);// 球pBall向前移动len长度是否与rt四壁相撞,如果相撞则Angle中存放的是反射回的方向,Pos中存放的是球恰与墙相撞时的圆心位置int Bisector(int a1,int a2);// 将a1、a2按照物理规则进行合成之后返回bool isTwoBallHit(ball* pActive,ball* pPassive,int *aActive,int *aPassive);// 考察主动球pActive是否与被动球pPassive相撞,相撞则将两球撞后方向分别填入aActive和aPassive之中//int DirectTwoPoint(POINT pt_src,POINT pt_dest);// 返回以pt_src为起点,指向pt_dest的射线方向public:HandleBall(){;}//bool init(HWND hWnd,int ball_r,int MoveLen);// 初始化函数完成成员变量的初始化以及相应对象的创建~HandleBall();// 完成垃圾清理工作void Show(COLORREF col,bool isErase);// 如果isErase为真则用col显示所有的球(可以用来擦除),否则col无效void Move(int mLen,bool UseDefault);// 移动此对象所有的球,如果UseDefault为真则用对象内部的移动位移量,为假则用mLenint DirectTwoPoint(POINT pt_src,POINT pt_dest);};#endif#include "stdafx.h"// ball类成员函数实现ball::ball(){this->col=COL_RED;this->pos.x=0;this->pos.y=0;this->r=0;}BOOL ball::init(POINT pos,unsigned int r, COLORREF col){this->pos=pos;this->r=r;this->col=col;return TRUE;}POINT ball::SetPos(POINT newPos){POINT tmpPos=this->pos;this->pos=newPos;return tmpPos;}POINT ball::GetPos(){return this->pos;}unsigned int ball::SetR(unsigned int newR){unsigned int tempR=this->r;this->r=newR;return tempR;}unsigned int ball::GetR(){return this->r;}COLORREF ball::SetCol(COLORREF newCol){COLORREF tempCol=this->col;this->col=newCol;return tempCol;}COLORREF ball::GetCol(){return this->col;}void ball::SetId(int id){this->id=id;}int ball::GetId(){return this->id;}BOOL ball::draw(HDC hdc,COLORREF col,bool isErase){BOOL bSuccess;HPEN hNewPen,hOldPen;HBRUSH hNewBrush,hOldBrush;// 如果不进行擦除,则用此球对象中存放的颜色创建画刷if(false==isErase)col=this->col;hNewPen=CreatePen(PS_NULL,0,0);hNewBrush=CreateSolidBrush(col);hOldPen=(HPEN) SelectObject(hdc,hNewPen);hOldBrush=(HBRUSH) SelectObject(hdc,hNewBrush);bSuccess=Ellipse(hdc,this->pos.x-this->r,this->pos.y-this->r,this->pos.x+this->r,this->pos.y+this->r);if(FALSE==bSuccess)return FALSE;SelectObject(hdc,hOldPen);SelectObject(hdc,hOldBrush);DeleteObject(hNewBrush);DeleteObject(hNewPen);return TRUE;}/*==================HandleBall类成员函数的实现==================*//*********************公有成员函数实现部分***********************/bool HandleBall::init(HWND hWnd,int ball_r,int MoveLen){int i;POINT pt;// 临时保存各球中心位置坐标RECT rt;// 保存窗体矩形区域SYSTEMTIME stime;GetSystemTime(&stime);WORD wCount=stime.wMilliseconds%100;while(wCount--)rand();// 以系统时间的微秒数为种子初始化rand函数,从而保证每一次得到的都不是一样的布局this->hWnd=hWnd;this->ball_r=ball_r;this->MoveLen=MoveLen;// 得到窗体大小GetClientRect(hWnd,&rt);for(i=0;i<BALLNUMBER;i++){// 生成球i以及其相应的移动方向角度this->pBalls[i]=new ball();this->BallAngles[i]=rand()%360;// 初始化球i:pt.x=(LONG)((abs(rand())%(int)(rt.right-2*ball_r))+ball_r);pt.y=(LONG)((abs(rand())%(int)(rt.bottom-2*ball_r))+ball_r);this->pBalls[i]->init(pt,ball_r,RGB(rand()%255,rand()%255,rand()%255));this->pBalls[i]->SetId(i);// 设置此球唯一标识}return true;}HandleBall::~HandleBall(){for(int i=0;i<BALLNUMBER;i++)delete this->pBalls[i];}void HandleBall::Show(COLORREF col,bool isErase){int i;HDC hdc=GetDC(hWnd);if(false==isErase){for(i=0;i<BALLNUMBER;i++)this->pBalls[i]->draw(hdc,0,false);}else{for(i=0;i<BALLNUMBER;i++)this->pBalls[i]->draw(hdc,col,true);}ReleaseDC(hWnd,hdc);}void HandleBall::Move(int mLen, bool UseDefault){if(true==UseDefault)mLen=this->MoveLen;for(int i=0;i<BALLNUMBER;i++)this->MoveOneBall(this->pBalls[i],this->BallAngles[i],mLen);}/*********************私有成员函数实现部分***********************//********************移动球**********************对pBall指向的球做如下移动:Nx=Ox+len*cos(Angle)Ny=Oy+len*sin(Angle)其中(Ox,Oy)为移动前的位置,而(Nx,Ny)为移动后的位置*/void HandleBall::MoveOneBall(ball *pBall,int Angle,int len){POINT OldPos,NewPos,tmpPos;RECT rt;int tempAngle;OldPos=pBall->GetPos();NewPos.x=OldPos.x+len*cos((float)AngToRad(Angle));NewPos.y=OldPos.y+len*sin((float)AngToRad(Angle));// 考虑与四壁碰撞情况GetClientRect(this->hWnd,&rt);if(this->isHitWall(pBall,Angle,len,rt,&tempAngle,&tmpPos)){this->BallAngles[pBall->GetId()]=tempAngle;// 改变球的运动方向NewPos.x=OldPos.x+len*cos((float)AngToRad(tempAngle));NewPos.y=OldPos.y+len*sin((float)AngToRad(tempAngle));pBall->SetPos(NewPos);}elsepBall->SetPos(NewPos);//考虑球之间碰撞问题int aActive,aPassive;for(int i=0;i<BALLNUMBER;i++){// 扫描全部不是pBall的球,并进行判断if(i!=pBall->GetId() && this->isTwoBallHit(pBall,this->pBalls[i],&aActive,&aPassive)){this->BallAngles[pBall->GetId()]=aActive;this->BallAngles[i]=aPassive;}}}/***********************反射算法*******************1、以aRef(亦即阻挡方向)为x轴正方向建立坐标系2、(360-aRef)即为新坐标轴按顺时针旋转与标准坐标轴重合所需要的最小角度*/int HandleBall::Reflect(int aSrc, int aRef){int aResult;// int n_aResult;// 新坐标轴下aResult角度int offset=(360-aRef)%360;// 两坐标轴之间的偏移量,参见以上定义int n_aSrc=(aSrc+offset)%360;// 新坐标轴下aSrc角度// 相当则不存在反射的可能,返回-1代表出错if(aSrc==aRef)return -1;n_aResult=360-n_aSrc;// 新坐标向标准坐标转换aResult=abs(n_aResult-offset);return aResult;}bool HandleBall::isHitWall(ball *pBall,int bdAngle, int len, RECT rt, int *Angle, POINT *Pos){POINT newPos;// 按规则移动后球的位置newPos.x=pBall->GetPos().x+len*cos((float)AngToRad(bdAngle));newPos.y=pBall->GetPos().y+len*sin((float)AngToRad(bdAngle));// pos初始化,返回此表明无效Pos->x=-1;Pos->y=-1;// 首先考虑与四个角碰撞的情况if(newPos.y<=rt.top && newPos.x<=rt.left){// 左上角*Angle=this->Reflect(bdAngle,135);return true;}if(newPos.y<=rt.top && newPos.x>=rt.right){// 右上角*Angle=this->Reflect(bdAngle,225);return true;}if(newPos.y>=rt.bottom && newPos.x<=rt.left){// 左下角*Angle=this->Reflect(bdAngle,45);return true;}if(newPos.y>=rt.bottom && newPos.x>=rt.right){// 右下角*Angle=this->Reflect(bdAngle,315);return true;}// 处理四壁碰撞的情况if(newPos.y<=rt.top){// 上*Angle=this->Reflect(bdAngle,0);return true;}if(newPos.y>=rt.bottom){// 下*Angle=this->Reflect(bdAngle,0);return true;}if(newPos.x<=rt.left){// 左*Angle=this->Reflect(bdAngle,90);return true;}if(newPos.x>=rt.right){// 右*Angle=this->Reflect(bdAngle,270);return true;}return false;}/*************************求两角平分线算法****************************1、当两角度同向(即差的绝对值小于180):aResult=(a1+a2)/22、当两角度反向:aResult=((a1+a2)/2+180)%360*/int HandleBall::Bisector(int a1, int a2){int Result;abs(a1-a2)>180? Result=(((a1+a2)/2+180)%360):Result=((a1+a2)/2);return Result;}/***********************************************************此中仍然采用自定义的坐标轴,因此所提到的象限定义如下:自右下方顺时针依次为一、二、三、四象限。*/int HandleBall::DirectTwoPoint(POINT pt_src,POINT pt_dest){float temp;//分四象限考虑情况if(pt_dest.x>pt_src.x && pt_dest.y>=pt_src.y){// 第一象限,包括0度temp=atan((float)((float)(pt_dest.y-pt_src.y)/(float)(pt_dest.x-pt_src.x)));return (int)RadToAng(temp);}if(pt_dest.x<=pt_src.x && pt_dest.y>pt_src.y){// 第二象限,包括90度temp=atan((float)((float)(pt_src.x-pt_dest.x)/(float)(pt_dest.y-pt_src.y)));return (int)RadToAng(temp)+90;}if(pt_dest.x<pt_src.x && pt_dest.y<=pt_src.y){// 第三象限,包括180度temp=(atan((float)((float)(pt_src.y-pt_dest.y)/(float)(pt_src.x-pt_dest.x))));return (int)RadToAng(temp)+180;}if(pt_dest.x>=pt_src.x && pt_dest.y<pt_src.y){// 第四象限,包括270度temp=(atan((float)((float)(pt_dest.x-pt_src.x)/(float)(pt_src.y-pt_dest.y))));return (int)RadToAng(temp)+270;}return -1;}bool HandleBall::isTwoBallHit(ball *pActive, ball *pPassive, int *aActive, int *aPassive){int RefDirect;// 两球相撞时,主动球的反射方向int aPerDirect;// 主动球先前方向int pPerDirect;// 被动球先前方向// 当两球心之间的距离小于两球半径之和时即相撞if(DISTANCE(pActive->GetPos(),pPassive->GetPos())<=(pActive->GetR()+pPassive->GetR())){aPerDirect=this->BallAngles[pActive->GetId()];pPerDirect=this->BallAngles[pPassive->GetId()];RefDirect=this->DirectTwoPoint(pPassive->GetPos(),pActive->GetPos());// 主动球返回方向由两球连线方向与自己原本方向所决定*aActive=this->Bisector(RefDirect,aPerDirect);// 被动球返回方向由主动球方向与自己原本方向所决定*aPassive=this->Bisector(aPerDirect,pPerDirect);return true;}elsereturn false;}// MoveBall.cpp : 定义应用程序的入口点。//#include "stdafx.h"#include "MoveBall.h"#define MAX_LOADSTRING 100#define MIN_WIDTH550#define MIN_HEIGHT  400#define TIMER_ID  100// 计时器ID号#define BALL_R  10// 球的半径#define MOVE_LEN  5// 球移动距离#define TIMER_INTERVAL20// 计时器时间间隔#define TRANS_TINTERVAL 10// 玻璃效果计数器时间间隔// 各timerID#define ID_BALL_MOVE100// 球运动计数器ID#define ID_TRANS_UP101// 淡入#define ID_TRANS_DOWN102// 淡出#define ID_AUTORUN103// 自动运行// 全局变量:HINSTANCE hInst;// 当前实例TCHAR szTitle[MAX_LOADSTRING];// 标题栏文本TCHAR szWindowClass[MAX_LOADSTRING];// 主窗口类名TCHAR szEvent[MAX_LOADSTRING];// 命名事件对象名称,用于检测程序运行的其他实例TCHAR szActiveExist[MAX_LOADSTRING];// 自定义消息名称TCHAR szBgMusic[MAX_LOADSTRING];// 背景音乐文件名UINT UM_ACTIVEEXIST=NULL;// 自定义消息,当检测到有此程序的其他实例在运行时,向其窗口发送此消息HBITMAP hbmpBg=NULL;// 背景位图句柄HBITMAP hbmpDream=NULL;// BITMAP  BgbmpInfo;// 背景位图信息BITMAPDreamBmpInfo;HMENU hMenu=NULL;// 菜单句柄bool isInit=true;    // 是否还正处于初始化中,Init函数将其设置为true,而其他的函数则将它设置为false,OnPaint根据此画图bool isStart=false;// 为true表明执行了startbool isStay=false;// 为true表明执行了staybool isFullScreen=false;// 是否全屏bool needContinue=false;// 当最小化窗口时设置,恢复时根据此重新启动bool canShowBall=false;// 是否可以在屏幕显示小球bool isTimerExist=false;// TIMER存在与否HandleBall HandleBallInst;// 对象实例int TransUp=0;// 窗体透明度int TransDown=255;// 此代码模块中包含的函数的前向声明:ATOMMyRegisterClass(HINSTANCE hInstance);BOOLInitInstance(HINSTANCE, int);LRESULT CALLBACKWndProc(HWND, UINT, WPARAM, LPARAM);INT_PTR CALLBACKAbout(HWND, UINT, WPARAM, LPARAM);void SetMenuItem(HWND hWnd);void Init(HWND hWnd,HandleBall *pHandleBall);// 初始化函数void StartOrStop(HWND hWnd,HandleBall *pHandleBall);// 开始与停止void StayOrMove(HWND hWnd,HandleBall *pHandleBall);// 暂停与继续BOOL OnSizing(HWND hWnd ,WPARAM wParam ,LPARAM lParam,LONG MinHeight,LONG MinWidth);bool FullScreen(HWND hWnd ,RECT *pRect,LONG *pStyle,bool isEnterFull);BOOL OnSize(HWND hWnd,WPARAM wParam,LPARAM lParam);//相应timer函数,本窗体多timer此函数一一处理void OnTimer(HWND hWnd,WPARAM wParam ,LPARAM lParam);// 保证程序运行实例唯一性的函数声明DWORD WINAPI WaitForExit(LPVOID lpParameter);bool isExist();// 加载背景音乐并写入文件bool LoadAndWriteMIDFile(HMODULE hModule,LPWSTR lpFileName);int APIENTRY _tWinMain(HINSTANCE hInstance,                     HINSTANCE hPrevInstance,                     LPTSTR    lpCmdLine,                     int       nCmdShow){UNREFERENCED_PARAMETER(hPrevInstance);UNREFERENCED_PARAMETER(lpCmdLine); // TODO: 在此放置代码。MSG msg;HACCEL hAccelTable;// 初始化全局字符串LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);LoadString(hInstance, IDC_MOVEBALL, szWindowClass, MAX_LOADSTRING);LoadString(hInstance, IDS_EVENT, szEvent,MAX_LOADSTRING);LoadString(hInstance, IDS_ACTIVEEXIST,szActiveExist,MAX_LOADSTRING);LoadString(hInstance, IDS_BGMUSIC,szBgMusic,MAX_LOADSTRING);// 注册自定义消息UM_ACTIVEEXIST=RegisterWindowMessage(szActiveExist);// 检测是否有其他实例正在运行if(isExist())return 0;// 如果存在则返回// 准备背景音乐LoadAndWriteMIDFile(hInstance,szBgMusic);MyRegisterClass(hInstance);// 加载位图if(hbmpBg=LoadBitmap(hInstance,MAKEINTRESOURCEW(IDB_BG))){GetObject(hbmpBg,sizeof(BgbmpInfo),&BgbmpInfo);}if(hbmpDream=LoadBitmap(hInstance,MAKEINTRESOURCEW(IDB_DREAM))){GetObject(hbmpDream,sizeof(DreamBmpInfo),&DreamBmpInfo);}// 执行应用程序初始化:if (!InitInstance (hInstance, nCmdShow)){return FALSE;}hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_MOVEBALL));// 主消息循环:while (GetMessage(&msg, NULL, 0, 0)){if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg)){TranslateMessage(&msg);DispatchMessage(&msg);}}if(hbmpBg && DeleteObject(hbmpBg))hbmpBg=NULL;if(hbmpDream && DeleteObject(hbmpDream))hbmpDream=NULL;return (int) msg.wParam;}////  函数: MyRegisterClass()////  目的: 注册窗口类。////  注释:////    仅当希望//    此代码与添加到 Windows 95 中的“RegisterClassEx”//    函数之前的 Win32 系统兼容时,才需要此函数及其用法。调用此函数十分重要,//    这样应用程序就可以获得关联的//    “格式正确的”小图标。//ATOM MyRegisterClass(HINSTANCE hInstance){WNDCLASSEX wcex;wcex.cbSize = sizeof(WNDCLASSEX);wcex.style= CS_HREDRAW | CS_VREDRAW;wcex.lpfnWndProc= WndProc;wcex.cbClsExtra= 0;wcex.cbWndExtra= 0;wcex.hInstance= hInstance;wcex.hIcon= LoadIcon(hInstance, MAKEINTRESOURCE(IDI_MOVEBALL));wcex.hCursor= LoadCursor(NULL, IDC_ARROW);wcex.hbrBackground= CreateSolidBrush(COL_BLACK);wcex.lpszMenuName= MAKEINTRESOURCE(IDC_MOVEBALL);wcex.lpszClassName= szWindowClass;wcex.hIconSm= LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));return RegisterClassEx(&wcex);}////   函数: InitInstance(HINSTANCE, int)////   目的: 保存实例句柄并创建主窗口////   注释:////        在此函数中,我们在全局变量中保存实例句柄并//        创建和显示主程序窗口。//BOOL InitInstance(HINSTANCE hInstance, int nCmdShow){   HWND hWnd;   hInst = hInstance; // 将实例句柄存储在全局变量中   hWnd = CreateWindowEx(WS_EX_LAYERED,szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,      CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);   if (!hWnd)   {      return FALSE;   }   //    SetLayeredWindowAttributes(hWnd,RGB(255,0,0),0,LWA_COLORKEY | LWA_ALPHA);   ShowWindow(hWnd, nCmdShow);   UpdateWindow(hWnd);   return TRUE;}////  函数: WndProc(HWND, UINT, WPARAM, LPARAM)////  目的: 处理主窗口的消息。////  WM_COMMAND- 处理应用程序菜单//  WM_PAINT- 绘制主窗口//  WM_DESTROY- 发送退出消息并返回////LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam){int wmId, wmEvent;PAINTSTRUCT ps;HDC hdc;HDC hCompatibleDC;// 兼容DCRECT WndRect,ClientRect;HMENU hSubMenu;static LONG WndStyle;// 保存窗体样式static RECT WndRt;// 保存窗体矩形区域if(message==UM_ACTIVEEXIST){SetLayeredWindowAttributes(hWnd,RGB(255,0,0),0,LWA_COLORKEY | LWA_ALPHA);SetTimer(hWnd,ID_TRANS_UP,TRANS_TINTERVAL,NULL);ShowWindow(hWnd,SW_SHOWNORMAL);return 1;}switch (message){case WM_CREATE:SetTimer(hWnd,ID_TRANS_UP,TRANS_TINTERVAL,NULL);// 操作菜单hMenu=GetMenu(hWnd);hSubMenu=GetSubMenu(hMenu,0);for(int i=1;i<9;i++)EnableMenuItem(hSubMenu,i,MF_BYPOSITION | MF_DISABLED | MF_GRAYED);SetMenuDefaultItem(hSubMenu,0,TRUE);// 调整窗体位置GetWindowRect(hWnd,&WndRect);SetWindowPos(hWnd,0,GetSystemMetrics(SM_CXSCREEN)/2-(WndRect.right-WndRect.left)/2,GetSystemMetrics(SM_CYSCREEN)/2-(WndRect.bottom-WndRect.top)/2,0,0, SWP_NOSIZE | SWP_NOZORDER | SWP_SHOWWINDOW);// 初始化对象Init(hWnd,&HandleBallInst);break;case WM_COMMAND:wmId    = LOWORD(wParam);wmEvent = HIWORD(wParam);// 分析菜单选择:switch (wmId){case IDM_ABOUT:DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);break;case IDM_EXIT:SetTimer(hWnd,ID_TRANS_DOWN,TRANS_TINTERVAL,NULL);break;case ID_INIT:// 初始化Init(hWnd,&HandleBallInst);break;case ID_START:// 启动StartOrStop(hWnd,&HandleBallInst);break;case ID_STOP:// 停止StartOrStop(hWnd,&HandleBallInst);break;case ID_PAUSE:// 暂停StayOrMove(hWnd,&HandleBallInst);break;case ID_CONTINUE: // 继续StayOrMove(hWnd,&HandleBallInst);break;case ID_FULLSCREEN:// 全屏显示ModifyMenu(GetSubMenu(hMenu,0),ID_FULLSCREEN,MF_BYCOMMAND | MF_STRING ,ID_NORMALSCREEN,L"退出全屏(&X)\tF5");// 隐藏菜单SetMenu(hWnd,NULL);// 调用函数进入全屏FullScreen(hWnd,&WndRt,&WndStyle,true);isFullScreen=true;break;case ID_NORMALSCREEN:// 退出全屏ModifyMenu(GetSubMenu(hMenu,0),ID_NORMALSCREEN,MF_BYCOMMAND | MF_STRING ,ID_FULLSCREEN,L"全屏显示(&F)\tF5");// 调用函数退出全屏FullScreen(hWnd,&WndRt,&WndStyle,false);// 显示菜单SetMenu(hWnd,hMenu);isFullScreen=false;break;default:return DefWindowProc(hWnd, message, wParam, lParam);}break;case WM_PAINT:hdc = BeginPaint(hWnd, &ps);// TODO: 在此添加任意绘图代码...if(isInit && (hCompatibleDC=CreateCompatibleDC(hdc))){// 处于初始化之中则显示背景图片GetClientRect(hWnd,&ClientRect);SelectObject(hCompatibleDC,hbmpBg);BitBlt(hdc,(ClientRect.right+ClientRect.left)/2-BgbmpInfo.bmWidth/2,(ClientRect.bottom+ClientRect.top)/2-BgbmpInfo.bmHeight/2,BgbmpInfo.bmWidth,BgbmpInfo.bmHeight,hCompatibleDC,0,0,SRCCOPY);DeleteDC(hCompatibleDC);}if(canShowBall)HandleBallInst.Show(0,false);if(!isInit && !isStart && (hCompatibleDC=CreateCompatibleDC(hdc))){// 非初始化之中且执行了停止动作GetClientRect(hWnd,&ClientRect);SelectObject(hCompatibleDC,hbmpDream);BitBlt(hdc,(ClientRect.right+ClientRect.left)/2-DreamBmpInfo.bmWidth/2,(ClientRect.bottom+ClientRect.top)/2-DreamBmpInfo.bmHeight/2,DreamBmpInfo.bmWidth,DreamBmpInfo.bmHeight,hCompatibleDC,0,0,SRCCOPY);DeleteDC(hCompatibleDC);}EndPaint(hWnd, &ps);break;case WM_RBUTTONDOWN:// 创建快捷菜单POINT pt;pt.x=MAKEPOINTS(lParam).x;pt.y=MAKEPOINTS(lParam).y;ClientToScreen(hWnd,&pt);TrackPopupMenu(GetSubMenu(hMenu,0),TPM_TOPALIGN | TPM_LEFTALIGN,// 标记位pt.x,pt.y,0,hWnd,0);break;case WM_TIMER:// 交给timer函数统一处理OnTimer(hWnd,wParam,lParam);break;case WM_CHAR:switch(wParam){case 0x20:// 空格StayOrMove(hWnd,&HandleBallInst);break;case 0x0D:  // 回车StartOrStop(hWnd,&HandleBallInst);break;case 0x1B:Init(hWnd,&HandleBallInst);break;}break;case WM_KEYDOWN:// 响应F5功能键if(wParam==VK_F5){if(isFullScreen){// 当前处于全屏,应退出全屏SendMessage(hWnd,WM_COMMAND,(WPARAM)ID_NORMALSCREEN,(LPARAM)0);return 0;}else {// 当前不是全屏,应进入全屏SendMessage(hWnd,WM_COMMAND,(WPARAM)ID_FULLSCREEN,(LPARAM)0);return 0;}}break;case WM_SIZE:OnSize(hWnd,wParam,lParam);break;case WM_SIZING:return OnSizing(hWnd,wParam,lParam,MIN_HEIGHT ,MIN_WIDTH);break;case WM_CLOSE:SetTimer(hWnd,ID_TRANS_DOWN,TRANS_TINTERVAL,NULL);break;case WM_DESTROY:PostQuitMessage(0);break;default:return DefWindowProc(hWnd, message, wParam, lParam);}return 0;}// “关于”框的消息处理程序。INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam){UNREFERENCED_PARAMETER(lParam);switch (message){case WM_INITDIALOG:return (INT_PTR)TRUE;case WM_COMMAND:if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL){EndDialog(hDlg, LOWORD(wParam));return (INT_PTR)TRUE;}break;}return (INT_PTR)FALSE;}void Init(HWND hWnd,HandleBall *pHandleBall){if(isTimerExist)KillTimer(hWnd,ID_BALL_MOVE);pHandleBall->init(hWnd,BALL_R,MOVE_LEN);InvalidateRect(hWnd,NULL,TRUE);isInit=true;canShowBall=false;isTimerExist=false;SetMenuItem(hWnd);SetTimer(hWnd,ID_AUTORUN,3000,NULL);}void StartOrStop(HWND hWnd,HandleBall *pHandleBall){if(isInit || (!isInit && !isStart))// 执行了初始化,或者初始化被抵消但没有执行Start{// 开始// 设置timer并将canShowBall设置为true//InvalidateRect(hWnd,NULL,TRUE);pHandleBall->init(hWnd,BALL_R,MOVE_LEN);SetTimer(hWnd,ID_BALL_MOVE,TIMER_INTERVAL,NULL);canShowBall=false;isStart=true;isTimerExist=true;isInit=false;isStay=false;}else if(!isInit && isStart)// 非初始化且执行了Start{// 停止KillTimer(hWnd,ID_BALL_MOVE);InvalidateRect(hWnd,NULL,TRUE);canShowBall=false;isStart=false;isTimerExist=false;isInit=false;isStay=false;}SetMenuItem(hWnd);}void StayOrMove(HWND hWnd,HandleBall *pHandleBall){if(!isInit && isStart && !isStay)// 非初始化且执行了Start且没有执行Stay{KillTimer(hWnd,ID_BALL_MOVE);canShowBall=true;isStay=true;isTimerExist=false;isInit=false;}else if(!isInit && isStart && isStay){SetTimer(hWnd,ID_BALL_MOVE,TIMER_INTERVAL,NULL);canShowBall=false;isStay=false;isTimerExist=true;isInit=false;}SetMenuItem(hWnd);}BOOL OnSizing(HWND hWnd ,WPARAM wParam ,LPARAM lParam,LONG MinHeight,LONG MinWidth){LONG NewWidth,NewHeight;RECT* pRect;// lParam is a Pointer point a RECT structure;// So we can get the Width and Height as followif(wParam!=WMSZ_BOTTOM && wParam!=WMSZ_BOTTOMLEFT&& wParam!=WMSZ_BOTTOMRIGHT&& wParam!=WMSZ_LEFT&& wParam!=WMSZ_RIGHT&& wParam!=WMSZ_TOP&& wParam!=WMSZ_TOPLEFT&& wParam!=WMSZ_TOPRIGHT)return FALSE;NewWidth=((RECT*)lParam)->right-((RECT*)lParam)->left;NewHeight=((RECT*)lParam)->bottom-((RECT*)lParam)->top;pRect=(RECT*)lParam;switch(wParam){case WMSZ_BOTTOM:if(NewHeight<MinHeight){pRect->bottom=pRect->top+MinHeight;return TRUE;}break;case WMSZ_BOTTOMLEFT:if(NewWidth<MinWidth || NewHeight<MinHeight){if(NewWidth<MinWidth)pRect->left=pRect->right-MinWidth;if(NewHeight<MinHeight)pRect->bottom=pRect->top+MinHeight;return TRUE;}break;case WMSZ_BOTTOMRIGHT:if(NewWidth<MinWidth || NewHeight < MinHeight){if(NewWidth<MinWidth)pRect->right=pRect->left+MinWidth;if(NewHeight < MinHeight)pRect->bottom=pRect->top+MinHeight;return TRUE;}break;case WMSZ_LEFT:if(NewWidth < MinWidth){pRect->left=pRect->right-MinWidth;return TRUE;}break;case WMSZ_RIGHT:if(NewWidth < MinWidth){pRect->right=pRect->left+MinWidth;return TRUE;}break;case WMSZ_TOP:if(NewHeight < MinHeight){pRect->top=pRect->bottom-MinHeight;return TRUE;}break;case WMSZ_TOPLEFT:if(NewWidth < MinWidth || NewHeight < MinHeight){if(NewWidth < MinWidth)pRect->left=pRect->right-MinWidth;if(NewHeight < MinHeight)pRect->top=pRect->bottom-MinHeight;return TRUE;}break;case WMSZ_TOPRIGHT:if(NewWidth < MinWidth || NewHeight < MinHeight){if(NewWidth < MinWidth)pRect->right=pRect->left+MinWidth;if(NewHeight < MinHeight)pRect->top=pRect->bottom-MinHeight;return TRUE;}break;default:return FALSE;}return FALSE;}BOOL OnSize(HWND hWnd,WPARAM wParam,LPARAM lParam){switch(wParam){case SIZE_RESTORED:// 从最小化恢复SetLayeredWindowAttributes(hWnd,RGB(255,0,0),0,LWA_COLORKEY | LWA_ALPHA);SetTimer(hWnd,ID_TRANS_UP,TRANS_TINTERVAL,NULL);if(needContinue){SendMessage(hWnd,WM_COMMAND,(WPARAM)ID_CONTINUE,(LPARAM)0);needContinue=false;}return true;case SIZE_MINIMIZED:if(!isInit && isStart && !isStay){//正在运行中,则将其暂停,且设置标准needContinueSendMessage(hWnd,WM_COMMAND,(WPARAM)ID_PAUSE,(LPARAM)0);needContinue=true;}return true;case SIZE_MAXIMIZED:SetLayeredWindowAttributes(hWnd,RGB(255,0,0),0,LWA_COLORKEY | LWA_ALPHA);SetTimer(hWnd,ID_TRANS_UP,TRANS_TINTERVAL,NULL);return true;}return false;}void SetMenuItem(HWND hWnd){HMENU hSubMenu;hSubMenu=GetSubMenu(hMenu,0);if(isInit){// 处于初始化状态EnableMenuItem(hSubMenu,ID_INIT,MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);// 初始化-disabledEnableMenuItem(hSubMenu,ID_START,MF_BYCOMMAND | MF_ENABLED);// 启动-enabledEnableMenuItem(hSubMenu,ID_STOP,MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);// 停止-disabledEnableMenuItem(hSubMenu,ID_PAUSE,MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);// 暂停-disabledEnableMenuItem(hSubMenu,ID_CONTINUE,MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);// 继续-enabled}else if(!isInit && isStart && !isStay){// 正处于启动运行状态EnableMenuItem(hSubMenu,ID_INIT,MF_BYCOMMAND | MF_ENABLED);EnableMenuItem(hSubMenu,ID_START,MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);EnableMenuItem(hSubMenu,ID_STOP,MF_BYCOMMAND | MF_ENABLED);EnableMenuItem(hSubMenu,ID_PAUSE,MF_BYCOMMAND | MF_ENABLED);EnableMenuItem(hSubMenu,ID_CONTINUE,MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);}else if(!isInit && isStart && isStay){// 正处于启动暂停状态EnableMenuItem(hSubMenu,ID_INIT,MF_BYCOMMAND | MF_ENABLED);EnableMenuItem(hSubMenu,ID_START,MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);EnableMenuItem(hSubMenu,ID_STOP,MF_BYCOMMAND | MF_ENABLED);EnableMenuItem(hSubMenu,ID_PAUSE,MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);EnableMenuItem(hSubMenu,ID_CONTINUE,MF_BYCOMMAND | MF_ENABLED);}else if(!isInit && !isStart){// 处于停止状态EnableMenuItem(hSubMenu,ID_INIT,MF_BYCOMMAND | MF_ENABLED);// 初始化-disabledEnableMenuItem(hSubMenu,ID_START,MF_BYCOMMAND | MF_ENABLED);// 启动-enabledEnableMenuItem(hSubMenu,ID_STOP,MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);// 停止-disabledEnableMenuItem(hSubMenu,ID_PAUSE,MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);// 暂停-disabledEnableMenuItem(hSubMenu,ID_CONTINUE,MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);// 继续-}}/*对hWnd操作,根据isEnterFull将窗体设置为全屏或者退出全屏isEnterFull=true;// 设为全屏isEnterFull=false;// 退出全屏当isEnterFull为真时,pRect返回正常窗口大小,pStyle返回正常的窗体样式。(为返回正常窗体,调用者必须保存此参数)当isEnterFull为假时,pRect用于传入正常窗口大小,pStyle传入正常的窗体样式。*/bool FullScreen(HWND hWnd ,RECT *pRect,LONG *pStyle,bool isEnterFull){LONG tmpStyle;int sx,sy;// 全屏宽和高if(isEnterFull)// 进入全屏{// 保存数据GetWindowRect(hWnd,pRect);*pStyle=GetWindowLong(hWnd,GWL_STYLE);tmpStyle=*pStyle;tmpStyle&=~WS_BORDER;// 边框tmpStyle&=~WS_CAPTION;// 标题栏tmpStyle&=~WS_SIZEBOX;// 不可推拉sx=GetSystemMetrics(SM_CXSCREEN);sy=GetSystemMetrics(SM_CYSCREEN);SetWindowLong(hWnd,GWL_STYLE,tmpStyle);SetWindowPos(hWnd,HWND_TOPMOST,0,0,sx,sy,SWP_SHOWWINDOW);return true;}else if(!isEnterFull)// 退出全屏{SetWindowLong(hWnd,GWL_STYLE,*pStyle);SetWindowPos(hWnd,HWND_NOTOPMOST,pRect->left,pRect->top,pRect->right-pRect->left,pRect->bottom-pRect->top,SWP_SHOWWINDOW);}return false;}// void OnTimer(HWND hWnd,WPARAM wParam ,LPARAM lParam){static bool isFirst=true;if(isFirst){TransUp=0;TransDown=255;isFirst=false;}switch(wParam){case ID_BALL_MOVE:// 球运动HandleBallInst.Show(COL_BLACK,true);HandleBallInst.Move(10,false);HandleBallInst.Show(0,false);break;case ID_TRANS_UP:// 淡入if(TransUp<=255){SetLayeredWindowAttributes(hWnd,RGB(255,0,0),TransUp,LWA_COLORKEY | LWA_ALPHA);TransUp+=3;}else {KillTimer(hWnd,ID_TRANS_UP);isFirst=true;}break;case ID_TRANS_DOWN:// 淡出if(TransDown>=0){SetLayeredWindowAttributes(hWnd,RGB(255,0,0),TransDown,LWA_COLORKEY | LWA_ALPHA);TransDown-=3;}else{KillTimer(hWnd,ID_TRANS_DOWN);PostQuitMessage(0);}break;case ID_AUTORUN:// 自动运行// 发送自动运行消息并销毁时间控件SendMessage(hWnd,WM_COMMAND,(WPARAM)ID_START,(LPARAM)0);KillTimer(hWnd,ID_AUTORUN);break;}}/*是否有此程序的实例正在运行,存在且能够得到其窗体句柄则发送消息将其激活否则将其关闭不存在则返回false*/ bool isExist(){HANDLE hEvent;HWND hWnd;if((hEvent=CreateEvent(NULL,TRUE,FALSE,szEvent))// 创建一个人工设置 , 初始为无信号的事件&& GetLastError()==ERROR_ALREADY_EXISTS){// 如果此程序有实例,则试图得到其窗口句柄if(hWnd=FindWindow(szWindowClass,szTitle)){SendNotifyMessage(hWnd,UM_ACTIVEEXIST,(WPARAM)0,(LPARAM)0);return true;}else {// 得到窗体句柄失败,则将其关闭SetEvent(hEvent);return false;}}CreateThread(NULL,0,WaitForExit,(LPVOID)hEvent,0,NULL);return false;}/*此线程只是一直等待直到lpParameter所标示的事件有信号则将当前进程关闭*/DWORD WINAPI WaitForExit(LPVOID lpParameter){WaitForSingleObject((HANDLE)lpParameter,INFINITE);TerminateProcess(GetCurrentProcess(),0);return 0;}bool LoadAndWriteMIDFile(HMODULE hModule,LPWSTR lpFileName){const SIZE_T FileLen=22097;HRSRC hRsrc;HGLOBAL hGlobal;LPVOID lpMidAddr=0;// 保存mid资源在内存位置HANDLE hFile;DWORD dwRet;// 加载资源并得到内存地址hRsrc=FindResource(hModule,L"#1122",L"MID");if(!hRsrc)return false;hGlobal=LoadResource(hModule,hRsrc);if(!hGlobal)return false;lpMidAddr=LockResource(hGlobal);if(!lpMidAddr)return false;hFile=CreateFile(lpFileName,GENERIC_READ | GENERIC_WRITE ,FILE_SHARE_READ,NULL,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL);if(!hFile)return false;if(!WriteFile(hFile,lpMidAddr,FileLen,&dwRet,NULL))return false;return true;}


 

原创粉丝点击