鱼C论坛

 找回密码
 立即注册
查看: 1707|回复: 3

[技术交流] 【学习笔记】方式A的时钟

[复制链接]
发表于 2012-12-6 11:38:16 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
方式A的时钟.ASM
================================================================================

;程序运行结构
;01:程序建立消息循环
;02:窗口过程中创建窗口发送消息定时器
;03:设置客户区为无效矩形(每秒执行一次)
;04:然后在PAINT消息中开始绘画
; 05:执行_ShowTime子程序来
;  06:执行_CalcClockParam子程序计算时钟的位置、大小等参数
;   07:比较客户区宽度和高度,以小的值作为时钟的直径
;  08:画时钟圆周上的点
;   09:调用_DrawDot画12个大圆点
;    10:调用_CalcX子程序:计算时钟圆周上某个角度对应的 X 坐标
;    11:调用_CalcY子程序:计算时钟圆周上某个角度对应的 X 坐标
;   12:调用_DrawDot画60个小圆点
;    13:调用_CalcX子程序:计算时钟圆周上某个角度对应的 X 坐标
;    14:调用_CalcY子程序:计算时钟圆周上某个角度对应的 X 坐标
;  15:画时钟指针
;   16:调用_DrawLine绘画秒针、计算线条两端的坐标
;   17:调用_DrawLine绘画分针、计算线条两端的坐标
;   18:调用_DrawLine绘画时针、计算线条两端的坐标
; 19:结束_ShowTime子程序
;20:退出
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
  .386
  .model flat, stdcall
  option casemap :none
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; Include 文件定义
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
include  windows.inc
include  user32.inc
includelib user32.lib
include  kernel32.inc
includelib kernel32.lib
include  Gdi32.inc
includelib Gdi32.lib
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; Equ 等值定义
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
ICO_MAIN equ  1000h
ID_TIMER equ  1
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 数据段
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
  .data?
hInstance dd  ?
hWinMain dd  ?
dwCenterX dd  ?    ;圆心X
dwCenterY dd  ?    ;圆心Y
dwRadius dd  ?    ;半径
  .const
szClassName db  '精简时钟',0
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 代码段
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
  .code
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 计算时钟的位置、大小等参数
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
_CalcClockParam proc
  local @stRect:RECT
  invoke GetClientRect,hWinMain,addr @stRect ;获取客户区矩形左上角和右下角
  ;invoke GetWindowRect,hWinMain,addr @stRect
  ;获取的是程序的窗口坐标,不是按屏幕坐标
  mov eax,@stRect.right    ;将右下角X坐标放入eax
  ;sub eax,@stRect.left    ;右下角X坐标减去左上角X坐标的值等于矩形宽度
  mov ecx,@stRect.bottom   ;将右下角Y坐标放入ecx
  ;sub ecx,@stRect.top    ;右下角Y坐标减去左上角Y坐标的值等于矩形高度
;*****************************************************************************************************************
; 比较客户区宽度和高度,以小的值作为时钟的直径
;*****************************************************************************************************************
  .if ecx > eax   ;高度大于宽度
   mov edx,eax    ;将宽度放入edx寄存器
   sub ecx,eax    ;高度减去宽度的值放入ecx,便于改变大小时,还是在中间
   shr ecx,1    ;将ecx的值除以2的1次方
   mov dwCenterX,0   ;将圆心x置0
   mov dwCenterY,ecx   ;将exc(宽高相差值的一半)放入圆心y
  .else    ;高度小于或等于宽度
   mov edx,ecx    ;将高度放入edx寄存器
   sub eax,ecx    ;宽度减去高度然后把差值放入eax,便于改变大小时,还是在中间
   shr eax,1    ;将eax的值除以2的1次方
   mov dwCenterX,eax   ;将差值放入圆心x
   mov dwCenterY,0   ;将0放入放入圆心y
  .endif
  shr edx,1     ;将距离短的高度或者宽度除以2的1次方
  mov dwRadius,edx    ;半径
  add dwCenterX,edx    ;圆心x加上半径
  add dwCenterY,edx    ;圆心y加上半径
  ret      ;得到圆心坐标(x,y)返回
_CalcClockParam endp
_dwPara180 dw 180     ;类型:字
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 计算时钟圆周上某个角度对应的 X 坐标
; X = 圆心X + Sin(角度) * 半径
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
_CalcX  proc _dwDegree,_dwRadius   ;角度,半径
  local @dwReturn    ;存储X坐标结果
  fild dwCenterX    ;将圆心x按整型放入st0(浮点栈顶)
  fild _dwDegree    ;将角度按整型放入st0(浮点栈顶),别的浮点数据栈+1
  fldpi      ;将圆周率压入浮点栈
  fmulp st(1),st     ;角度*圆周率(没有操作数的隐含规则:st(1),st(0)),清空参数1和参数2并将结果放入栈顶(st0)
  ;fistp @dwReturn
  ;操作完成后st(1)和st(0)会被清空,别的栈会上升,结果保存在st(0)
  ;如果fmul操作后带有参数,那么栈不会清空,并且把结果存放至参数1
  ;参数后面加上P代表弹出栈顶,fmulp st(1),st中的结果放在了参数1中,不是st(0)
  fild _dwPara180    ;将类型为【字】的数据180按整型放入栈顶
  fdivp st(1),st     ;【角度*Pi】/180并把结果存放至st0
  ;参数1和参数2都会被清空,结果存在栈顶
  fsin      ;Sin(角度*圆周率/180)
  fild _dwRadius    ;将半径按整型放入st0
  fmulp st(1),st(0)     ;半径*Sin(角度*圆周率/180)【隐含操作数:st(1),st(0)】
  faddp st(1),st(0)     ;X+半径*Sin(角度*圆周率/180)
  fistp @dwReturn    ;将st(0)按整型存储至@dwReturn并将st(0)弹出
  mov eax,@dwReturn    ;将数据放入eax
  ret
_CalcX  endp
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 计算时钟圆周上某个角度对应的 Y 坐标
; Y = 圆心Y - Cos(角度) * 半径
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
_CalcY  proc _dwDegree,_dwRadius   ;;角度,半径
  local @dwReturn    ;存储Y坐标结果
  fild dwCenterY    ;将圆心y按整型放入栈顶
  fild _dwDegree    ;将角度按整型放入栈顶
  fldpi      ;将圆周率放入栈顶
  fmulp st(1),st(0)     ;(角度*圆周率)st(0)和st(1)相乘后清空st(0)和st(1)并把结果放入栈顶
  ;参数后面加上P代表弹出栈顶,fmulp st(1),st中的结果放在了参赛1中,不是st(0)
  fild _dwPara180    ;将180按整型存入栈顶
  fdivp st(1),st     ;参数1除以参数2后清空st(0)和st(1)并将结果放入栈顶
  fcos      ;Cos(角度*圆周率/180)
  fild _dwRadius    ;将半径存放至栈顶
  fmulp st(1),st(0)     ;半径*Cos(角度*圆周率/180)【隐含操作数:st(1),st(0)】
  fsubp st(1),st     ;参数1减去参数2,将结果存放至st(1),并且将st(0)弹出
  fistp @dwReturn    ;将st(0)按照整型存储至@dwReturn并弹出st(0)
  mov eax,@dwReturn    ;将数据放入eax
  ret
_CalcY  endp
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 按照 _dwDegreeInc 的步进角度,画 _dwRadius 为半径的小圆点
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
_DrawDot proc _hDC,_dwDegreeInc,_dwRadius  ;设备环境句柄,步进角度,小圆点半径
  local @dwNowDegree,@dwR   ;当前角度,局部半径
  local @dwX1,@dwY1    ;X和Y坐标
  mov @dwNowDegree,0    ;当前角度置0
  mov eax,dwRadius    ;将半径放入eax
  sub eax,5     ;半径减去5
  mov @dwR,eax    ;将运算过的半径放入局部半径
  .while @dwNowDegree <= 360   
   finit     ;浮点堆栈清空
;*****************************************************************************************************************
; 计算小圆点的圆心坐标
;*****************************************************************************************************************
   invoke _CalcX,@dwNowDegree,@dwR ;调用_CalcX子程序,参数:当前角度,局部半径
   ;计算时钟圆周上某个角度对应的 X 坐标
   mov @dwX1,eax
   invoke _CalcY,@dwNowDegree,@dwR ;调用_CalcY子程序,参数:当前角度,局部半径
   ;计算时钟圆周上某个角度对应的 Y 坐标
   mov @dwY1,eax   ;eax是Y坐标
   
   mov esi,@dwX1
   add esi,_dwRadius
   push esi
   pop @dwX1
   sub esi,_dwRadius
   sub esi,_dwRadius
   mov edi,@dwY1
   add edi,_dwRadius
   push edi
   pop @dwY1
   sub edi,_dwRadius
   sub edi,_dwRadius
   
   invoke Ellipse,_hDC,esi,edi,@dwX1,@dwY1
   mov eax,_dwDegreeInc   ;步进角度放入eax
   add @dwNowDegree,eax  ;角度相加
  .endw
  ret
_DrawDot endp
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 秒针、分针、时针:画 _dwDegree 角度的线条,半径=时钟半径-参数_dwRadiusAdjust
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
_DrawLine proc _hDC,_dwDegree,_dwRadiusAdjust  ;参数:设备环境句柄,当前的角度,需要校正长度的值
  local @dwR     ;存储校正长度的秒针
  local @dwX1,@dwY1,@dwX2,@dwY2  ;局部变量:从(x1,y1)画线到(x2,y2)
  mov eax,dwRadius    ;存储半径至eax
  sub eax,_dwRadiusAdjust   ;校正指针长度
  mov @dwR,eax    ;存储指针长度至局部变量@dwR
;*****************************************************************************************************************
; 计算线条两端的坐标
;*****************************************************************************************************************
  invoke _CalcX,_dwDegree,@dwR   ;计算时钟圆周上某个角度对应的 X1 坐标、参数:角度,半径
  mov @dwX1,eax    ;将x1放入局部变量@dwX1
  invoke _CalcY,_dwDegree,@dwR   ;计算时钟圆周上某个角度对应的 Y1 坐标、参数:角度,半径
  mov @dwY1,eax    ;将y1放入局部变量@dwY1
  add _dwDegree,180    ;角度增加180度(半个圆)
  invoke _CalcX,_dwDegree,8   ;计算时钟圆周上某个角度对应的 X2 坐标、参数:角度,半径:8
  mov @dwX2,eax    ;将x2放入局部变量@dwX2
  invoke _CalcY,_dwDegree,8   ;计算时钟圆周上某个角度对应的 Y2 坐标、参数:角度,半径:8
  mov @dwY2,eax    ;将y2放入局部变量@dwY2
  invoke MoveToEx,_hDC,@dwX1,@dwY1,NULL  ;指定当前新的(x,y)坐标位置
  invoke LineTo,_hDC,@dwX2,@dwY2   ;从当前位置画直线到(x,y),超过了圆心点
  ret
_DrawLine endp
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
_ShowTime proc _hWnd,_hDC
  local @stTime:SYSTEMTIME   ;结构体包含系统时间相关
  pushad
  invoke GetLocalTime,addr @stTime   ;将时间信息返回到@stTime结构体中
  invoke _CalcClockParam    ;该子程序计算时钟的位置、大小等参数
;*****************************************************************************************************************
; 画时钟圆周上的点
;*****************************************************************************************************************
  invoke CreateSolidBrush,255   ;获取预定义库存中的画笔、刷子、字体、或调色板的句柄
  invoke SelectObject,_hDC,eax   ;设置在某个设备环境句柄中使用什么绘图工具
  invoke _DrawDot,_hDC,360/12,3   ;该子程序画12个大圆点:设备环境句柄,步进角度,半径
  invoke _DrawDot,_hDC,360/60,1   ;该子程序画60个小圆点:设备环境句柄,步进角度,半径
;*****************************************************************************************************************
; 画时钟指针
;*****************************************************************************************************************
  invoke CreatePen,PS_SOLID,1,0   ;黑色画笔
  ;该函数创建一个逻辑画笔,它有指定的样式,宽度和颜色,能被任何DC选择为当前画笔
  ;nPenStyle :画笔工作的样式
;PS_SOLID  :实心笔
;PS_DASH  :短线式笔
;PS_DOT   :点式笔
;PS_DASHDOT  :点线笔
;PS_DASHDOTDOT  :双点线笔
;PS_NULL   :笔不可见
;PS_INSIDEFRAME   :实线线条,和PS_SOLID相同,但是如果画笔宽度大于1像素时,宽度会像内部扩展
  ;nWidth  :指定的宽度(逻辑单位)
  ;crColor  :笔的基准颜色
  invoke SelectObject,_hDC,eax   ;设置设备环境使用实心笔来绘画
  invoke DeleteObject,eax    ;删除上一次使用的绘画工具
  movzx eax,@stTime.wSecond   ;将当前秒值扩展为双字放入eax
  mov ecx,360/60    ;将每秒的度数6放入ecx
  mul ecx     ;秒针度数 = 秒 * 360/60
  invoke _DrawLine,_hDC,eax,5   ;参数:设备环境句柄,当前的角度,需要校正长度的值
;*****************************************************************************************************************
  invoke CreatePen,PS_SOLID,2,255   ;创建画笔参数:实心笔、宽度为2、颜色红色
  invoke SelectObject,_hDC,eax   ;设置画笔为这个设备环境服务
  invoke DeleteObject,eax    ;删除上次的绘画工具
  movzx eax,@stTime.wMinute   ;当前分钟值扩展为双字放入eax
  mov ecx,360/60    ;将分钟度数为6放入ecx
  mul ecx     ;分针度数 = 分 * 360/60
  invoke _DrawLine,_hDC,eax,20   ;参数:设备环境句柄,当前的角度,需要校正长度的值
;*****************************************************************************************************************
  invoke CreatePen,PS_SOLID,3,250*10000h  ;创建画笔参数:实心笔、宽度为3、颜色蓝色
  invoke SelectObject,_hDC,eax   ;设置画笔为这个设备环境服务
  invoke DeleteObject,eax    ;删除上次的绘画工具
  movzx eax,@stTime.wHour   ;当前时钟值扩展为双字放入eax
  .if eax >= 12    ;如果大于12小时则减去12
   sub eax,12
  .endif
  mov ecx,360/12    ;将每个时钟间隔度数放入ecx
  mul ecx     ;eax = 时钟间隔度数*几点钟(小于<12)
  movzx ecx,@stTime.wMinute   ;将当前分钟放入ecx
  shr ecx,1     ;将ecx除以2的1次方
  add eax,ecx     ;eax = 当前时钟角度加上分钟角度的一半
  invoke _DrawLine,_hDC,eax,40   ;参数:设备环境句柄,当前的角度,需要校正长度的值
;*****************************************************************************************************************
  invoke GetStockObject,NULL_PEN   ;取得空画笔的句柄
  invoke SelectObject,_hDC,eax   ;设置设备环境句柄为空画笔
  invoke DeleteObject,eax    ;删除上一次使用的绘画工具
  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 ;将客户区改变为无效区域,TRUE代表擦除背景
  .elseif eax == WM_PAINT   ;绘画窗口的消息
   invoke BeginPaint,hWnd,addr @stPS ;开始绘画,将要绘画的信息放入@stPS结构体中,返回值为设备环境句柄
   invoke _ShowTime,hWnd,eax  ;执行子程序,参数1为窗口句柄,参数2为设备环境句柄
   invoke EndPaint,hWnd,addr @stPS  ;结束绘画
  .elseif eax == WM_CREATE   ;创建窗口的消息
   invoke SetTimer,hWnd,ID_TIMER,1000,NULL ;创建1s执行一次的定时器
;*****************************************************************************************************************
  .elseif eax == WM_RBUTTONUP   ;单击右键,退出
   invoke KillTimer,hWnd,ID_TIMER  ;清理定时器
   invoke DestroyWindow,hWinMain  ;摧毁窗口
   invoke PostQuitMessage,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
  invoke CreateHatchBrush,HS_DIAGCROSS,200*100h ;设置背景颜色
  mov @stWndClass.hbrBackground,eax
  mov @stWndClass.lpszClassName,offset szClassName
  invoke RegisterClassEx,addr @stWndClass
;*****************************************************************************************************************
; 建立并显示窗口
;*****************************************************************************************************************
  invoke CreateWindowEx,WS_EX_CLIENTEDGE or WS_EX_TOPMOST,offset szClassName,offset szClassName,WS_OVERLAPPEDWINDOW,550,200,240,250,\
   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


方式A的时钟.RC

=========================================================================================

#include  <resource.h>
//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
//宏命令
//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
#define  ICO_MAIN 0x1000   //图标
//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
ICO_MAIN ICON  "Main.ico"

想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
发表于 2012-12-6 12:41:07 | 显示全部楼层
写得不错啊,赞一个,来坐个沙发吧
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
 楼主| 发表于 2012-12-6 12:49:35 | 显示全部楼层
给大家参考吧

方式A的时钟.rar

227.22 KB, 阅读权限: 10, 下载次数: 6

想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
发表于 2012-12-6 12:54:15 | 显示全部楼层
赞一个。。。。。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2024-11-18 06:41

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表