现在的位置: 首页 > 综合 > 正文

Bitmap位图应用1 —— Win32的数字时钟

2013年06月16日 ⁄ 综合 ⁄ 共 4318字 ⁄ 字号 评论关闭

学习编程离不开实战演练——用所掌握的技术来实现相应的功能,今天来玩一玩Win32的位图Bitmap,写一个数字时钟

 

我们先来看看这个数字时钟的需求:

(1)可以用ASCII码的数字,但是不太美观,因此需要做一个位图,完美模拟电子表的数字(我亲自做了一个,待会儿上传)

(2)如何将位图贴到我们的程序中

a)先将位图加载到内存中

我们先来看看msdn:

HBITMAP LoadBitmap(
  HINSTANCE hInstance,  // handle to application instance
  LPCTSTR lpBitmapName  // name of bitmap resource
);

因此不难知道使用方法,用法我没必要多少,我只想提一点:

我们的位图是保存在硬盘(ROM)中的,程序是在内存(RAM)中的,因此首先需将位图加载到内存中,我们的程序才能直接使用。LoadBitmap函数就是其这样一个作用

类似的函数还有:LoadIcon、LoadCursor等等

b)将位图贴到我们的程序中

这个需要用到很常用的、也是很有用的函数:

BOOL BitBlt(
  HDC hdcDest, // handle to destination DC
  int nXDest,  // x-coord of destination upper-left corner
  int nYDest,  // y-coord of destination upper-left corner
  int nWidth,  // width of destination rectangle
  int nHeight, // height of destination rectangle
  HDC hdcSrc,  // handle to source DC
  int nXSrc,   // x-coordinate of source upper-left corner
  int nYSrc,   // y-coordinate of source upper-left corner
  DWORD dwRop  // raster operation code
);

这个函数有一个很强大的功能:

我们可以按照自己的需要截取位图的一部分,这就意味着有时我们的程序只需要那么几张、或是仅仅一张位图,就能达到使用更多张位图的效果

它的具体用法可以参见给出的完整代码

(3)获取系统时间

这个就没什么多说的了,直接使用以下函数就ok:

GetLocalTime(LPSYSTEMTIME)//传递一个SYSTEMTIME类型的指针  就是系统时间

(4)时间的处理

我就仅仅介绍我的做法:

int	x, y, cxBitmap, cyBitmap;
//x、y表示位图贴在窗口客户区的坐标,cxBitmap、cyBitmap表示位图的长宽。为了方便起见,以上四个全是全局变量

 

时间处理代码:

VOID DrawTime(HDC hdc, WORD time, BOOL isSecond)
{
	HDC		hdcMem;
	int		decade, uint;//十位和个位

	hdcMem = CreateCompatibleDC(hdc);	//兼容DC
	SelectObject(hdcMem, hBitmap);		//选中位图

	//判断当前时间是否小于10 ,如果小于10 , 就要用0来填十位
	if(time < 10)
	{
		decade	= 0;
		uint	= time;
	}
	else
	{
		decade	= time / 10;
		uint	= time % 10;
	}
	
	//绘制十位
	x += cxBitmap;
	BitBlt(hdc, x, y, cxBitmap, cyBitmap / 12, hdcMem, 0, (11 - decade) * (cyBitmap / 12), SRCCOPY);
	
	//绘制个位
	x += cxBitmap;
	BitBlt(hdc, x, y, cxBitmap, cyBitmap / 12, hdcMem, 0, (11 - uint) * (cyBitmap / 12), SRCCOPY);
	
	//如果不是秒 , 那么个位后面加一个冒号
	if(!isSecond)
	{
		x += cxBitmap;
		BitBlt(hdc, x, y, cxBitmap, cyBitmap / 12, hdcMem, 0, cyBitmap / 12, SRCCOPY);
	}

	DeleteDC(hdcMem);
}

 

(5)设定一个时间计时器,每隔一秒调用一次(这个不是本次的重点,以后会讲到的,其实很简单^_^)

 

 

下面直接上完整的源代码:(有注释)

//数字时钟
#include<windows.h>
#include"resource.h"

//重新定义窗口风格(不可改变大小)
#define WS_NORESIZEWINDOW	(WS_OVERLAPPED     | \
                             WS_CAPTION        | \
                             WS_SYSMENU        | \
                             WS_MINIMIZEBOX)
//设定计时器ID
#define ID_TIMER	1

HBITMAP	hBitmap;
int		x, y, cxBitmap, cyBitmap;

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

int WINAPI WinMain(HINSTANCE hInstance,
				   HINSTANCE hPrevInstance,
                   PSTR szCmdLine,
				   int iCmdShow)
{
	static	TCHAR	szAppName[] = TEXT("NumClock");
	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))
	{
		MessageBox(NULL, TEXT("This program requires Windows NT!"),
			szAppName, MB_ICONERROR);
		return 0;
	}
	
	hwnd = CreateWindow(szAppName,
						TEXT("NumClock Demo"),
						WS_NORESIZEWINDOW,
						(1366 - 200) / 2,
						(768 - 150) / 2,
						200,
						150,
						NULL,
						NULL,
						hInstance,
						NULL);

	ShowWindow(hwnd, iCmdShow);
	UpdateWindow(hwnd);

	while(GetMessage(&msg, NULL, 0, 0))
	{
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}
	
	return msg.wParam;
}

VOID DrawTime(HDC hdc, WORD time, BOOL isSecond)
{
	HDC		hdcMem;
	int		decade, uint;//十位和个位

	hdcMem = CreateCompatibleDC(hdc);	//兼容DC
	SelectObject(hdcMem, hBitmap);		//选中位图

	//判断当前时间是否小于10 ,如果小于10 , 就要用0来填十位
	if(time < 10)
	{
		decade	= 0;
		uint	= time;
	}
	else
	{
		decade	= time / 10;
		uint	= time % 10;
	}
	
	//绘制十位
	x += cxBitmap;
	BitBlt(hdc, x, y, cxBitmap, cyBitmap / 12, hdcMem, 0, (11 - decade) * (cyBitmap / 12), SRCCOPY);
	
	//绘制个位
	x += cxBitmap;
	BitBlt(hdc, x, y, cxBitmap, cyBitmap / 12, hdcMem, 0, (11 - uint) * (cyBitmap / 12), SRCCOPY);
	
	//如果不是秒 , 那么个位后面加一个冒号
	if(!isSecond)
	{
		x += cxBitmap;
		BitBlt(hdc, x, y, cxBitmap, cyBitmap / 12, hdcMem, 0, cyBitmap / 12, SRCCOPY);
	}

	DeleteDC(hdcMem);
}

//计时器回调函数
VOID CALLBACK TimerProc(HWND hwnd, UINT uMsg, UINT idEvent, DWORD dwTime)
{
	HDC		hdc;
	SYSTEMTIME st;

	GetLocalTime(&st);//获取本地系统时间

	hdc = GetDC(hwnd);

	x = 33;
	y = 51;
	
	DrawTime(hdc, st.wHour, FALSE);		//绘制小时数字
	DrawTime(hdc, st.wMinute, FALSE);	//绘制分钟数字
	DrawTime(hdc, st.wSecond, TRUE);	//绘制秒钟数字
	
	ReleaseDC(hwnd, hdc);
}

//窗口回调函数
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{	
	switch(message)
	{
	//初始化参数
	case WM_CREATE:
		{
			HINSTANCE	hInstance;
			BITMAP		bitmap;

			hInstance = ((LPCREATESTRUCT)lParam)->hInstance;//获取窗口的实例句柄
			hBitmap = LoadBitmap(hInstance, MAKEINTRESOURCE(IDB_BITMAP1));
			GetObject(hBitmap, sizeof(BITMAP), &bitmap);

			cxBitmap = bitmap.bmWidth;
			cyBitmap = bitmap.bmHeight;

			SetTimer(hwnd, ID_TIMER, 1000, TimerProc);//计时器开始
		}
		return 0 ;

	case WM_DESTROY:
		PostQuitMessage(0);
		return 0;
	}

	return DefWindowProc(hwnd, message, wParam, lParam);
}

 

 

 

好了到此为止,数字时钟算是完成了,下面来看看运行效果:

 

怎么样,是不是和电子表的显示很相似呢?呵呵……

 

 

点击下载位图资源

抱歉!评论已关闭.