WIN32汇编语言教程:第07章 图形操作 · 7.3 创建和使用位图(4)
首先简单分析一下程序的结构,主程序中先用RegisterClassEx注册窗口类,再用CreateWindowEx建立窗口的过程,这是标准的创建窗口的代码,惟一的特殊之处是建立窗口使用的窗口风格是WS_POPUP或WS_SYSMENU,这样建立的窗口没有标题栏,以便以后实现圆形的窗口。
程序中的坐标算法和7.2节的Clock.asm是一样的,所以有些子程序沿用了上一个程序中的相关子程序,如计算坐标的_CalcX和_CalcY,绘画指针的_DrawLine子程序等。
在窗口过程的WM_CREATE消息中,程序用CreatePopupMenu创建了一个Popup菜单,用来在按下右键的时候弹出该菜单,并多次调用AppendMenu创建需要的菜单项(相关内容见第05章的“菜单”一节)。然后,程序用CreateEllipticRgn建立一个区域,并用SetWindowRgn函数把窗口设置成圆形,这两个函数在本章的最后一节介绍。接下来,程序用SetWindowPos函数把窗口设置为“总在最前面”。在WM_CREATE消息的最后,程序调用_CreateBackGround和_CreateClockPic创建背景位图和时钟位图,这是这一节中要详细介绍的内容。和前面简单的时钟程序类似,本程序也建立了一个周期为1s的定时器用来刷新屏幕。
在选择菜单后的WM_COMMAND消息中,程序调用_DeleteBackGround子程序先删除原有的位图,再调用_CreateBackGround和_CreateClockPic子程序产生新的背景位图和时钟位图,最后调用InvalidateRect函数产生WM_PAINT消息重新绘画客户区。
程序有个特殊之处是对WM_LBUTTONDOWN消息的处理,由于建立的窗口没有标题栏,所以无法用拖动标题栏的方法移动窗口,为了在窗口客户区拖动鼠标就能够移动窗口,必须欺骗Windows,让它认为是在拖动标题栏,所以在WM_LBUTTONDOWN消息中,程序发送位置为HTCAPTION的WM_NCLBUTTONDOWN消息,这样就相当于告诉Windows用户按下的是标题栏。头尾处的两个SetCursor函数是为了按下鼠标时让光标变成一个抓住东西的手的形状。
整个程序的结构采用图7.1中的B结构,也就是说窗口客户区的绘画代码和产生时钟位图的代码是分开的,程序中建立了两个位图当做缓冲数据,第一个位图是背景位图,在_CreateBackGround子程序中建立,只有在程序初始化以及在菜单中选择了不同的背景和边框后才需要调用这个子程序,以便建立新的背景图片;第二个位图是要输出到屏幕的时钟位图,它在_CreateClockPic子程序中建立,时钟位图是通过将背景位图拷贝过来,再根据当前时间画上指针得到的,程序在WM_TIMER消息中每秒重画一次新的时钟图片,并用InvalidateRect函数产生一个WM_PAINT消息将这个位图拷贝到屏幕上,当其他原因产生WM_PAINT消息时,程序并不从头开始产生背景位图和时钟位图等图片,而是直接从时钟图片中拷贝数据到屏幕上。
好了,接下来继续分析_CreateBackGround和_CreateClockPic子程序是如何对位图进行处理的。
7.3.2 创建和使用位图
所有绘图函数的操作对象都是“设备环境”,对位图操作也不例外。为了对位图使用GDI函数,需要使用CreateCompatibleDC函数为位图建立一个DC,然后使用SelectObject函数将位图选入这个DC中,这样,所有对这个DC的绘图操作实际上就是在操作这个位图。每一个需要操作的位图都需要单独为它创建一个DC。
程序中常常使用在资源中预定义的位图,但也有使用未初始化的位图的情况,如例子程序的背景位图和时钟位图一开始就是未初始化的,它们是程序开始运行后才被创建的。
为了建立一个未初始化的位图,可以使用以下的函数:
invoke CreateCompatibleBitmap,hDC,dwWidth,dwHeight mov hBitmap1,eax ;方法1 invoke CreateBitmap,dwWidth,dwHeight,dwPlanes,dwBitsPerPel,NULL mov hBitmap2,eax ;方法2