<Win32_2>Bitmap位图应用1 ------ Win32的数字时钟



本文由BlueCoder编写   转载请说明出处:

http://blog.csdn.net/crocodile__/article/details/9448103

我的邮箱:bluecoder@yeah.net    欢迎大家和我交流编程心得

我的微博:BlueCoder_黎小华    欢迎光临^_^


学习编程离不开实战演练——用所掌握的技术来实现相应的功能,今天来玩一玩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:

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


(4)时间的处理

我就仅仅介绍我的做法:

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

 

时间处理代码:

  1. VOID DrawTime(HDC hdc, WORD time, BOOL isSecond)  
  2. {  
  3.     HDC     hdcMem;  
  4.     int     decade, uint;//十位和个位  
  5.   
  6.     hdcMem = CreateCompatibleDC(hdc);   //兼容DC  
  7.     SelectObject(hdcMem, hBitmap);      //选中位图  
  8.   
  9.     //判断当前时间是否小于10 ,如果小于10 , 就要用0来填十位  
  10.     if(time < 10)  
  11.     {  
  12.         decade  = 0;  
  13.         uint    = time;  
  14.     }  
  15.     else  
  16.     {  
  17.         decade  = time / 10;  
  18.         uint    = time % 10;  
  19.     }  
  20.       
  21.     //绘制十位  
  22.     x += cxBitmap;  
  23.     BitBlt(hdc, x, y, cxBitmap, cyBitmap / 12, hdcMem, 0, (11 - decade) * (cyBitmap / 12), SRCCOPY);  
  24.       
  25.     //绘制个位  
  26.     x += cxBitmap;  
  27.     BitBlt(hdc, x, y, cxBitmap, cyBitmap / 12, hdcMem, 0, (11 - uint) * (cyBitmap / 12), SRCCOPY);  
  28.       
  29.     //如果不是秒 , 那么个位后面加一个冒号  
  30.     if(!isSecond)  
  31.     {  
  32.         x += cxBitmap;  
  33.         BitBlt(hdc, x, y, cxBitmap, cyBitmap / 12, hdcMem, 0, cyBitmap / 12, SRCCOPY);  
  34.     }  
  35.   
  36.     DeleteDC(hdcMem);  
  37. }  
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)设定一个时间计时器,每隔一秒调用一次(这个不是本次的重点,以后会讲到的,其实很简单^_^)

  

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

  1. //数字时钟  
  2. #include<windows.h>  
  3. #include"resource.h"  
  4.   
  5. //重新定义窗口风格(不可改变大小)  
  6. #define WS_NORESIZEWINDOW   (WS_OVERLAPPED     | \  
  7.                              WS_CAPTION        | \  
  8.                              WS_SYSMENU        | \  
  9.                              WS_MINIMIZEBOX)  
  10. //设定计时器ID  
  11. #define ID_TIMER    1  
  12.   
  13. HBITMAP hBitmap;  
  14. int     x, y, cxBitmap, cyBitmap;  
  15.   
  16. LRESULT CALLBACK WndProc(HWNDUINTWPARAMLPARAM);  
  17.   
  18. int WINAPI WinMain(HINSTANCE hInstance,  
  19.                    HINSTANCE hPrevInstance,  
  20.                    PSTR szCmdLine,  
  21.                    int iCmdShow)  
  22. {  
  23.     static  TCHAR   szAppName[] = TEXT("NumClock");  
  24.     HWND            hwnd;  
  25.     MSG             msg;  
  26.     WNDCLASS        wndclass;  
  27.       
  28.     wndclass.style          = CS_HREDRAW | CS_VREDRAW;  
  29.     wndclass.lpfnWndProc    = WndProc;  
  30.     wndclass.cbClsExtra     = 0;  
  31.     wndclass.cbWndExtra     = 0;  
  32.     wndclass.hInstance      = hInstance;  
  33.     wndclass.hIcon          = LoadIcon(NULL, IDI_APPLICATION);  
  34.     wndclass.hCursor        = LoadCursor(NULL, IDC_ARROW);  
  35.     wndclass.hbrBackground  = (HBRUSH)GetStockObject(WHITE_BRUSH);  
  36.     wndclass.lpszMenuName   = NULL;  
  37.     wndclass.lpszClassName  = szAppName;  
  38.       
  39.     if(!RegisterClass(&wndclass))  
  40.     {  
  41.         MessageBox(NULL, TEXT("This program requires Windows NT!"),  
  42.             szAppName, MB_ICONERROR);  
  43.         return 0;  
  44.     }  
  45.       
  46.     hwnd = CreateWindow(szAppName,  
  47.                         TEXT("NumClock Demo"),  
  48.                         WS_NORESIZEWINDOW,  
  49.                         (1366 - 200) / 2,  
  50.                         (768 - 150) / 2,  
  51.                         200,  
  52.                         150,  
  53.                         NULL,  
  54.                         NULL,  
  55.                         hInstance,  
  56.                         NULL);  
  57.   
  58.     ShowWindow(hwnd, iCmdShow);  
  59.     UpdateWindow(hwnd);  
  60.   
  61.     while(GetMessage(&msg, NULL, 0, 0))  
  62.     {  
  63.         TranslateMessage(&msg);  
  64.         DispatchMessage(&msg);  
  65.     }  
  66.       
  67.     return msg.wParam;  
  68. }  
  69.   
  70. VOID DrawTime(HDC hdc, WORD time, BOOL isSecond)  
  71. {  
  72.     HDC     hdcMem;  
  73.     int     decade, uint;//十位和个位  
  74.   
  75.     hdcMem = CreateCompatibleDC(hdc);   //兼容DC  
  76.     SelectObject(hdcMem, hBitmap);      //选中位图  
  77.   
  78.     //判断当前时间是否小于10 ,如果小于10 , 就要用0来填十位  
  79.     if(time < 10)  
  80.     {  
  81.         decade  = 0;  
  82.         uint    = time;  
  83.     }  
  84.     else  
  85.     {  
  86.         decade  = time / 10;  
  87.         uint    = time % 10;  
  88.     }  
  89.       
  90.     //绘制十位  
  91.     x += cxBitmap;  
  92.     BitBlt(hdc, x, y, cxBitmap, cyBitmap / 12, hdcMem, 0, (11 - decade) * (cyBitmap / 12), SRCCOPY);  
  93.       
  94.     //绘制个位  
  95.     x += cxBitmap;  
  96.     BitBlt(hdc, x, y, cxBitmap, cyBitmap / 12, hdcMem, 0, (11 - uint) * (cyBitmap / 12), SRCCOPY);  
  97.       
  98.     //如果不是秒 , 那么个位后面加一个冒号  
  99.     if(!isSecond)  
  100.     {  
  101.         x += cxBitmap;  
  102.         BitBlt(hdc, x, y, cxBitmap, cyBitmap / 12, hdcMem, 0, cyBitmap / 12, SRCCOPY);  
  103.     }  
  104.   
  105.     DeleteDC(hdcMem);  
  106. }  
  107.   
  108. //计时器回调函数  
  109. VOID CALLBACK TimerProc(HWND hwnd, UINT uMsg, UINT idEvent, DWORD dwTime)  
  110. {  
  111.     HDC     hdc;  
  112.     SYSTEMTIME st;  
  113.   
  114.     GetLocalTime(&st);//获取本地系统时间  
  115.   
  116.     hdc = GetDC(hwnd);  
  117.   
  118.     x = 33;  
  119.     y = 51;  
  120.       
  121.     DrawTime(hdc, st.wHour, FALSE);     //绘制小时数字  
  122.     DrawTime(hdc, st.wMinute, FALSE);   //绘制分钟数字  
  123.     DrawTime(hdc, st.wSecond, TRUE);    //绘制秒钟数字  
  124.       
  125.     ReleaseDC(hwnd, hdc);  
  126. }  
  127.   
  128. //窗口回调函数  
  129. LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)  
  130. {     
  131.     switch(message)  
  132.     {  
  133.     //初始化参数  
  134.     case WM_CREATE:  
  135.         {  
  136.             HINSTANCE   hInstance;  
  137.             BITMAP      bitmap;  
  138.   
  139.             hInstance = ((LPCREATESTRUCT)lParam)->hInstance;//获取窗口的实例句柄  
  140.             hBitmap = LoadBitmap(hInstance, MAKEINTRESOURCE(IDB_BITMAP1));  
  141.             GetObject(hBitmap, sizeof(BITMAP), &bitmap);  
  142.   
  143.             cxBitmap = bitmap.bmWidth;  
  144.             cyBitmap = bitmap.bmHeight;  
  145.   
  146.             SetTimer(hwnd, ID_TIMER, 1000, TimerProc);//计时器开始  
  147.         }  
  148.         return 0 ;  
  149.   
  150.     case WM_DESTROY:  
  151.         PostQuitMessage(0);  
  152.         return 0;  
  153.     }  
  154.   
  155.     return DefWindowProc(hwnd, message, wParam, lParam);  
  156. }  
//数字时钟
#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);
}


 

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

 

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

 

点击下载数字时钟

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,我来给你举个例子。 假设我们已经有了一个包含字形数据的 myFont.c 文件,我们需要将其添加到 ESP32-S3 项目中。可以将该文件放置在项目根目录下的 components 文件夹中,然后在 CMakeLists.txt 文件中添加以下内容: ``` idf_component_register(SRCS "myFont.c" INCLUDE_DIRS "") ``` 这样就可以在项目中使用 myFont 字体了。 接下来,在主函数中调用 `lv_font_get_glyph_bitmap` 函数,实现绘制字形。下面是一个简单的例子: ```c #include "lvgl/lvgl.h" #include "myFont.h" int main(void) { // 初始化 LVGL lv_init(); // 创建屏幕对象 lv_obj_t * scr = lv_disp_get_scr_act(NULL); // 创建标签对象 lv_obj_t * label = lv_label_create(scr, NULL); // 设置标签文字 lv_label_set_text(label, "Hello, world!"); // 设置字体 lv_font_t * font = &myFont; // 使用 myFont 字体 lv_label_set_style(label, LV_LABEL_STYLE_MAIN, font); // 获取字形数据 const lv_font_glyph_dsc_t * glyph_dsc = lv_font_get_glyph_dsc(font, 'H'); const uint8_t * bitmap = lv_font_get_glyph_bitmap(font, glyph_dsc); // 绘制字形 lv_area_t area = {50, 50, glyph_dsc->w_px, glyph_dsc->h_px}; lv_draw_label_dsc_t label_dsc; label_dsc.font = font; label_dsc.color = LV_COLOR_RED; lv_draw_bitmap(bitmap, &area, &label_dsc); // 运行 LVGL while(1) { lv_task_handler(); } return 0; } ``` 这段代码创建了一个标签对象,并将其设置为使用 myFont 字体。然后,通过 `lv_font_get_glyph_dsc` 和 `lv_font_get_glyph_bitmap` 函数获取字形数据,并使用 `lv_draw_bitmap` 函数绘制字形。最后,进入 LVGL 运行循环,等待事件的发生。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值