`
java-mans
  • 浏览: 11427799 次
文章分类
社区版块
存档分类
最新评论

windows程序设计(4):分解扫雷程序之计时器

 
阅读更多

上次忘了说明,因为我想做一个逼真的扫雷,所以我的扫雷程序的位图都是从windowsXP下面的扫雷里来的。具体是怎么获取位图的呢?我的是windows7系统,里面的扫雷跟XP的不一样,我先下载了一个Xp下的扫雷,然后使用一个软件:PE Explore来获取位图,然后在我的程序中装载这些位图就行了。

这次要做的是一个计时器,扫雷的的计时器不是时、分、秒;类型的,而是百秒、十秒、秒类型的。

看过雷区翻盖的朋友,也该都能明白,计时器显示时间的变化其实也是在画图,不停的换0~9这几个数字的图。那么现在只需要一个时钟消息,让他来触发画图就可以了。而windows中,恰好有这个消息:WM_TIMER。这个消息是如何使用的呢?

当你要触发计时器时,先要设置计时器(SetTimer);当时钟到来以后,在WM_TIMER写响应程序;在不需要计时器的时候,注销计时器(KillTimer)。这也是我的程序的大体思路:当WM_CREATE消息到来时,先把时钟画出来,画在右上角,值全为0;当单击鼠标左键时开始计时,时钟到来的时候,发送自定义消息;在自定义消息下画图(显示出时钟跳动),当WM_DESTROY消息到来时,注销掉时钟。

程序中定义的宏是用来表示计时器用的,因为我们完全可以设置多个计时器,每个计时器时钟间隔不同来完成扫雷中计时器功能。但我并不是这样做的,而是设置了一个一秒跳动一下的计时器,并且设置了一个整型变量sec记录秒数。sec%10表明了是多少秒;(sec%100)/10表示的是几十秒(这里主要是因为直接整除10会出现错误的结果,所以先把百位去掉了);sec/100表明的是几百秒。

啰嗦了这么多,我们就看看程序吧!

#include <windows.h>
#include "resource.h"

#define ID_TIMER_1   1


//自定义消息
#define WM_MYMSG (WM_USER + 100) 

LRESULT CALLBACK WndProc (HWND,UINT,WPARAM,LPARAM);

int WINAPI WinMain(HINSTANCE hInstance,		//当前实例句柄
				   HINSTANCE hPrevInstance, //先前实例句柄
				   LPSTR lpCmdLine,			//命令行
				   int nCmdShow)			//显示状态
{
	static TCHAR szAppName[] = TEXT("我的计时器");
	//窗口句柄
	HWND hwnd;
	//消息
	MSG msg;
	//窗口类
	WNDCLASS wndclass;
	//窗口风格:当移动窗口或者改变大小时重绘窗口
	wndclass.style		   =  CS_HREDRAW | CS_VREDRAW;
	//指明回调函数
	wndclass.lpfnWndProc   = WndProc;
	//额外的比特用来确认下一个窗口类的位置,暂时不用
	wndclass.cbClsExtra    = 0;
	//额外的比特用来确认下一个窗口实例的位置,暂时不用
	wndclass.cbWndExtra    = 0;
	//实例句柄
	wndclass.hInstance     = hInstance;
	//装载图标
	wndclass.hIcon		   = LoadIcon(NULL, IDI_APPLICATION);
	//装载光标
	wndclass.hCursor       = LoadCursor(NULL,IDC_ARROW);
	//
	wndclass.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH);
	//菜单:暂时没有
	wndclass.lpszMenuName  = NULL;
	//窗口类名
	wndclass.lpszClassName = szAppName;

	//注册窗口
	if(!RegisterClass(&wndclass))
	{
		return -1;
	}

	//创建窗口
	hwnd = CreateWindow(szAppName,				//窗口类的名称,必须是已经注册的
						TEXT("计时器"),			//窗口标题
						WS_OVERLAPPEDWINDOW,	//窗口风格
						CW_USEDEFAULT,			//X坐标
						CW_USEDEFAULT,			//Y坐标
						CW_USEDEFAULT,			//宽度
						CW_USEDEFAULT,			//高度
						NULL,					//父窗口句柄
						NULL,					//菜单窗口句柄
						hInstance,				//高级版本的windos忽略
						NULL);					//

	//显示窗口
	ShowWindow(hwnd,SW_SHOWNA);

	//更新窗口
	UpdateWindow(hwnd);

	//消息循环
	while(GetMessage(&msg,NULL,0,0))
	{
		
		TranslateMessage(&msg);
		//将消息给窗口
		DispatchMessage(&msg);

	}

	return msg.wParam;

}
//回调函数:本程序的主要功能是设计一个计时器
LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	//位图句柄
	static HBITMAP hBitmap_clc;
	//客户区大小
	static int cxClient,cyClient;
	//资源大小
	static int cxSource_clc,cySource_clc;
	//位图结构的信息
	BITMAP bitmap_clc;
	//设备内容句柄
	HDC hdc,hdcMem;
	//实例句柄
	HINSTANCE hInstance;
	//坐标信息
	int x,y;
	//绘图结构信息
	PAINTSTRUCT ps;

	//计时用的变量
	static int sec = 0; 
	switch(message)
	{
	//创建消息:装载位图,获取位图信息
	case WM_CREATE:
		//获得实例句柄
		hInstance = ((LPCREATESTRUCT)lParam)->hInstance;
		//装载位图
		hBitmap_clc = LoadBitmap(hInstance, MAKEINTRESOURCE  (IDB_BITMAP1));
		//获取位图的信息,放到bitmap_clc里面去
		GetObject(hBitmap_clc,sizeof(BITMAP),&bitmap_clc);
		//每个数字的长和宽
		cxSource_clc = bitmap_clc.bmWidth;
		cySource_clc = bitmap_clc.bmHeight/12;
		return 0;

	//获取当前客户区的大小
	case WM_SIZE:
		cxClient = LOWORD(lParam);
		cyClient = HIWORD(lParam);
		return 0;

	//绘图消息:设置默认的贴图
	case WM_PAINT:
		hdc = BeginPaint (hwnd, &ps);
		//给指定的设备创建兼容的内存设备内容
		hdcMem = CreateCompatibleDC(hdc);
		//把对象选到设备内容中:参数为设备内容句柄,对象句柄
		SelectObject(hdcMem,hBitmap_clc);
		//开始画图
		//贴图位置:最右边是1秒的,左边一点是10秒的,再左边一点是100秒的,刚开始全为0		
		BitBlt(hdc,cxClient-cxSource_clc,  0,cxSource_clc,cySource_clc,hdcMem,0,cySource_clc*11,SRCCOPY);
		BitBlt(hdc,cxClient-cxSource_clc*2,0,cxSource_clc,cySource_clc,hdcMem,0,cySource_clc*11,SRCCOPY);
		BitBlt(hdc,cxClient-cxSource_clc*3,0,cxSource_clc,cySource_clc,hdcMem,0,cySource_clc*11,SRCCOPY);
		DeleteDC(hdcMem);
		EndPaint (hwnd, &ps); 
		return 0;

	//鼠标左键点击:开始计时
	case WM_LBUTTONDOWN:
		SetTimer(hwnd,ID_TIMER_1,1000,NULL);
		return 0;

	//时钟到来:发出声音,发送自定义消息
	case WM_TIMER:
		MessageBeep(MB_ICONASTERISK);
		sec++;
		//发送自定义消息
		SendMessage(hwnd,WM_MYMSG,wParam,lParam); 
		return 0;
	//自定义消息,开始画图改变时钟的值
	case WM_MYMSG:
		hdc = GetDC(hwnd);
		hdcMem =  CreateCompatibleDC(hdc);
		SelectObject(hdcMem,hBitmap_clc);
		//开始画图
		//数字的位置:0是第12个,位置为cySource_clc*11,1是第11个,位置为cySource_clc*10,以此类推
		BitBlt(hdc,cxClient-cxSource_clc,  0,cxSource_clc,cySource_clc,hdcMem,0,cySource_clc*(11-sec%10),SRCCOPY);
		BitBlt(hdc,cxClient-cxSource_clc*2,0,cxSource_clc,cySource_clc,hdcMem,0,cySource_clc*(11-(sec%100)/10),SRCCOPY);
		BitBlt(hdc,cxClient-cxSource_clc*3,0,cxSource_clc,cySource_clc,hdcMem,0,cySource_clc*(11-sec/100),SRCCOPY);
		DeleteDC(hdcMem);
		ReleaseDC(hwnd,hdc);
		return 0;

	case WM_DESTROY:
		PostQuitMessage(0);
		KillTimer(hwnd,ID_TIMER_1);
		return 0;
	}
	//缺省处理
	return DefWindowProc (hwnd, message, wParam, lParam);
}


如果你使用的不是windows扫雷自带的那些位图,肯定就会有错误喽!

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics