⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 007.txt

📁 会变语言实现的一些程序
💻 TXT
📖 第 1 页 / 共 5 页
字号:
    mov   @dwY2,eax

    invoke  MoveToEx,_hDC,@dwX1,@dwY1,NULL

    invoke  LineTo,_hDC,@dwX2,@dwY2

 

    ret

 

_DrawLine   endp

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

_ShowTime     proc     _hWnd,_hDC

    local @stTime:SYSTEMTIME

 

    pushad

    invoke  GetLocalTime,addr @stTime

      invoke  _CalcClockParam

;********************************************************************

; 画时钟圆周上的点

;********************************************************************

    invoke  GetStockObject,BLACK_BRUSH

    invoke  SelectObject,_hDC,eax

  invoke  _DrawDot,_hDC,360/12,3  ;画12个大圆点

  invoke  _DrawDot,_hDC,360/60,1  ;画60个小圆点

;********************************************************************

; 画时钟指针

;********************************************************************

    invoke  CreatePen,PS_SOLID,1,0

    invoke  SelectObject,_hDC,eax

    invoke  DeleteObject,eax

    movzx eax,@stTime.wSecond

    mov   ecx,360/60

  mul ecx ;秒针度数 = 秒 * 360/60

    invoke  _DrawLine,_hDC,eax,15

;********************************************************************

      invoke  CreatePen,PS_SOLID,2,0

    invoke  SelectObject,_hDC,eax

    invoke  DeleteObject,eax

    movzx eax,@stTime.wMinute

    mov   ecx,360/60

  mul ecx ;分针度数 = 分 * 360/60

    invoke  _DrawLine,_hDC,eax,20

;********************************************************************

      invoke  CreatePen,PS_SOLID,3,0

      invoke  SelectObject,_hDC,eax

      invoke  DeleteObject,eax

      movzx eax,@stTime.wHour

      .if   eax >=    12

      sub   eax,12

    .endif

    mov   ecx,360/12

    mul   ecx

      movzx ecx,@stTime.wMinute

    shr   ecx,1

      add   eax,ecx

      invoke  _DrawLine,_hDC,eax,30

;********************************************************************

    popad

    ret

 

_ShowTime   endp

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

_ProcWinMain       proc     uses ebx edi esi hWnd,uMsg,wParam,lParam

    local @stPS:PAINTSTRUCT 

 

    mov   eax,uMsg

      .if   eax ==    WM_TIMER

      invoke    InvalidateRect,hWnd,NULL,TRUE

    .elseif eax ==    WM_PAINT

      invoke    BeginPaint,hWnd,addr @stPS

      invoke    _ShowTime,hWnd,eax

     


      invoke    EndPaint,hWnd,addr @stPS

    .elseif eax ==    WM_CREATE

      invoke    SetTimer,hWnd,ID_TIMER,1000,NULL

;********************************************************************

      .elseif eax ==    WM_CLOSE

      invoke    KillTimer,hWnd,ID_TIMER

      invoke    DestroyWindow,hWinMain

      invoke    PostQuitMessage,NULL

;********************************************************************

    .else

      invoke DefWindowProc,hWnd,uMsg,wParam,lParam

      ret

      .endif

;********************************************************************

      xor eax,eax

      ret

 

_ProcWinMain     endp

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

_WinMain     proc

    local @stWndClass:WNDCLASSEX

    local @stMsg:MSG

 

    invoke  GetModuleHandle,NULL

    mov   hInstance,eax

;********************************************************************

; 注册窗口类

;********************************************************************

      invoke  RtlZeroMemory,addr @stWndClass,sizeof @stWndClass

    invoke  LoadIcon,hInstance,ICO_MAIN

    mov   @stWndClass.hIcon,eax

      mov   @stWndClass.hIconSm,eax

    invoke  LoadCursor,0,IDC_ARROW

    mov   @stWndClass.hCursor,eax

    push     hInstance

    pop   @stWndClass.hInstance

    mov   @stWndClass.cbSize,sizeof WNDCLASSEX

      mov   @stWndClass.style,CS_HREDRAW or CS_VREDRAW

    mov   @stWndClass.lpfnWndProc,offset _ProcWinMain

    mov   @stWndClass.hbrBackground,COLOR_WINDOW + 1

    mov   @stWndClass.lpszClassName,offset szClassName

    invoke  RegisterClassEx,addr @stWndClass

;********************************************************************

; 建立并显示窗口

;********************************************************************

      invoke  CreateWindowEx,WS_EX_CLIENTEDGE,\

      offset szClassName,offset szClassName,\

      WS_OVERLAPPEDWINDOW,\

      100,100,250,270,\

      NULL,NULL,hInstance,NULL

      mov   hWinMain,eax

      invoke  ShowWindow,hWinMain,SW_SHOWNORMAL

        invoke  UpdateWindow,hWinMain

;********************************************************************

; 消息循环

;********************************************************************

    .while  TRUE

      invoke    GetMessage,addr @stMsg,NULL,0,0

      .break    .if eax == 0

      invoke    TranslateMessage,addr @stMsg

      invoke    DispatchMessage,addr @stMsg

    .endw

    ret

_WinMain     endp

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

start:

    call     _WinMain

    invoke  ExitProcess,NULL

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

    end   start

下面简单分析一下程序的结构。

程序首先用标准的方法建立了一个窗口,在窗口的初始化消息WM_CREATE中用SetTimer建立了一个周期为1秒的定时器,用来在窗口的客户区中绘画时钟。这个定时器在WM_CLOSE消息中用KillTimer函数撤销。在定时器消息中,程序用InvalidateRect函数让整个客户区失效,相当于让Windows在消息循环中放入一条WM_PAINT消息,整个时钟的绘画在WM_PAINT消息中完成。

在WM_PAINT消息中程序用标准的方法调用BeginPaint函数获取窗口客户区的hDC,以便在上面绘画时钟,在消息返回的时候用EndPaint函数释放hDC,两个函数的中间,程序把hDC传给_ShowTime子程序,由这个子程序完成整个绘画工作。

在第6章中已经讲到:获取系统时间不能依赖于WM_TIMER消息的计数,所以在_ShowTime子程序的开始,程序调用GetLocalTime来获取当前的系统时间,并根据这个时间来绘画时钟的时、分、秒指针。由于绘画的过程很快,所以整个程序的结构使用前面图7.1中所示的A结构,也就是每次有WM_PAINT消息的时候,程序总是重画整个客户区,所以读者在速度比较慢的计算机上运行这个程序时,可能会看到有个闪烁的过程,因为程序每次总是先将整个客户区清除成背景色(InvalidateRect函数最后的TRUE参数要求Windows在发送WM_PAINT消息前清除客户区),然后绘画四周的刻度,最后画上指针。绘画刻度是由_DrawDot子程序完成的,绘画指针是由_DrawLine子程序完成的。

GetLocalTime后面的_CalcClockParam子程序根据客户区的尺寸计算时钟尺寸参数,它比较客户区高度和宽度,以其中的较小值用做时钟的直径,计算得到的圆心最后存放于全局变量dwCenterX和dwCenterY中,计算得到的半径存放于dwRadius中。

程序中有两个公用的子程序:_CalcX和_CalcY,它们用来计算角度对应的坐标,如图7.5所示,时钟0点时间是从垂直方向开始的,以时间值为角度配合Windows的默认坐标系,对应某个时间点(x,y),x应该是圆心x加上角度的正弦值乘以半径,y应该是圆心y减去角度的余弦值乘以半径。_CalcX和_CalcY输入的参数是角度_dwDegree和半径_dwRadius。子程序中使用80x86的协处理器指令,首先将角度值换算成弧度值——乘以π并除以180,然后用上面分析的公式进行浮点计算并将结果返回。



图7.5  时钟程序的坐标计算

在接下来的内容中,先介绍一些绘画操作的背景知识。

7.2.1  画笔和画刷

GDI中的绘画函数有3大类:画点、画线和画填充区域。使用过Photoshop等图形软件的读者一定知道,在画线之前需要选择一种画笔,这样画出来的线条都是基于这种画笔的;同样,填充一个区域之前需要选择一种画刷,这样整个填充区域将重复使用这个画刷的颜色或图案。

GDI中也有同样的画笔和画刷的概念,画笔、画刷以及其他一些GDI中要使用的东西,包括字体、区域、路径、图案和位图统称GDI中的“对象”,通过SelectObject函数可以指定一个DC当前使用的对象对应哪个对象句柄,称为“当前对象”,当设置了一个当前对象的时候,以后和这种对象相关的函数都将使用当前对象,直到再次用SelectObject选择新的对象为止。比如选择了新的画笔后,以后所有画线函数画出来的线条样式都是由这个画笔决定的,而选择了新的画刷后,则所有填充函数填充的样式都将使用这个画刷。

SelectObject函数的用法是:

  invoke  SelectObject,hDC,hGDIObject

  mov hOldObject,eax

其中参数hGDIObject就是对象的句柄,它可以是位图句柄、画笔句柄、画刷句柄、字体句柄或区域句柄,函数会根据句柄的种类自动替换原有的对象,并将原来使用的对象句柄返回(当对象类型是区域的时候除外),如果DC中原来没有设置当前对象,那么函数的返回值是GDI_ERROR或NULL。
     


1. 使用预定义的画笔和画刷

Windows预定义了一些常用的画笔和画刷,在程序中可以用GetStockObject来获取它们的句柄,Stock的中文含义是“常备的、库存的”,所以这个函数字面上的意思就是“获取常用的对象”,注意并没有类似于GetStockPen或GetStockBrush之类的函数,所有获取常用对象的操作统一使用GetStockObject函数。

GetStockObject函数的用法是:

  invoke  GetStockObject,fnObject

  mov hObject,eax

fnObject参数是预定义的对象类型,可以是表7.2所示的取值。

表7.2  GDI中的常用对象

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -