[新手上路]批处理新手入门导读[视频教程]批处理基础视频教程[视频教程]VBS基础视频教程[批处理精品]批处理版照片整理器
[批处理精品]纯批处理备份&还原驱动[批处理精品]CMD命令50条不能说的秘密[在线下载]第三方命令行工具[在线帮助]VBScript / JScript 在线参考
返回列表 发帖

[游戏娱乐] 批处理动画彩色指针时钟2.4

批处理指针时钟2.4

历史版本说明:原 2.0 效率过低, 代码及附件已删除,7楼及15楼的2.11代码已作为附件转移到本楼, 至2009-12-13此时, 最终版 彩色2.4都未曾再有更新


确实说了不再更新的, 可余兴未了啊, 哈哈,
最后2.4版代码就不贴了, 有兴趣者请下载本楼的附件,
加了彩色绘图处理, 再也难在大尺寸的钟面下做到显示秒针还每秒刷新了, 在5--6的大小下还勉强接近每秒刷新.
除非哪位有特牛的机器, 还有得一看了
看看截图吧:






批处理指针时钟2.3(单色)




特别感谢 百度 批处理吧: liuzhaonan11 和 批处理之家: netbenton
liuzhaonan11 在看到我的 1.0 版: http://tieba.baidu.com/f?kz=673033192 后,
自己写了一个有秒针的: http://tieba.baidu.com/f?kz=673179640
给了我许多启发.
netbenton 特别提出了 for 循环的令牌代换方案, 使一维串的高效操作得以实现.
也感谢批处理之家: batman, 523066680, liuxuchu1989 的关注和肯定
当然接受 batman 在 16 楼的建议, 这个时钟不再准备更新, 即使尚未好好测试.
最后贴出 2.3 版代码
  1. title 指针时钟2.3 by neorobin 谢: liuzhaonan11 netbenton
  2. rem 三角函数采用 6°间隔变量列表预设, 指针绘图采用 Bresenham 直线算法, 屏幕缓存变量采用一维串变量 strScr.
  3. rem 主程序采用了 先绘图, 后 "预算" 的方法, 即绘出当前时间的钟面图后, 立即计算好未来下一秒的钟面绘图,
  4. rem 当时间到达未来下一秒时, 就可在最小的延迟时间后 显示出钟面图.
  5. rem
  6. rem getNextSec 过程出于避免代码过长的考虑, 采用了日期的不完全正确计算方式,
  7. rem 在一些情况下会出现错误日期. 但钟面显示不用此日期, 故无影响.
  8. rem
  9. rem 时间正向变化 1 秒后才会触发表盘更新, 一个负向时间调整会引起表面 "停止"
  10. rem 但至多 2 秒后将再次与系统时钟同步.
  11. @echo off
  12. msg %username% /time:60 请右键单击时钟窗口标题栏, 选择“属性”-^>“字体”选项卡,“点阵字体”,大小: 6 x 12,以得到更好的显示效果
  13. setlocal enabledelayedexpansion
  14. color 9f
  15. set /a "size=19, HandS=size-2, HandM=HandS-3, HandH=HandM-3, rScale=size-1, width=2*size+1"
  16. set /a "indexMax=(2*size+1)*(2*size+1)"
  17. set /a "xStart=size, xEnd=-size, yStart=-size, yEnd=size"
  18. set /a "Cols=(size*2+1)*2, Lines=size*2+1+1"
  19. (set PntCenter=◎)&(set PntH=●)&(set PntM=○)&(set PntS=·)&(set PntB=▓)
  20. (set RomanNumbers=ⅠⅡⅢⅣⅤⅥⅦⅧⅨⅩⅪⅫ)
  21. (set days=一二三四五六日一)
  22. set /a "leftSpaces=size*2+1-13-1" & (set Blanks=)
  23. for /l %%i in (1,1,!leftSpaces!) do (set Blanks= !Blanks!)
  24. mode con cols=!Cols! Lines=!Lines!
  25. call :math
  26. (set strScr=) & rem 全角空格初始化
  27. for /l %%i in (1,1,!indexMax!) do (set strScr= !strScr!)
  28. (call :creatDial strScr !PntB!)
  29. :loop
  30. cls & (set /p=!strScr!!Blanks! !date! !futureTime!!Blanks!<nul)
  31. for %%i in (!PntH!,!PntM!,!PntS!) do ( rem 擦除指针
  32.   for /f "tokens=1" %%p in ("!PntB!") do (set strScr=!strScr:%%i=%%p!)
  33. )
  34. (call :getNextSec futureTime futureDate)
  35. (call :drawScale strScr) & rem 当指针设置过长时, 会覆盖刻度, 需要重绘.
  36. for %%i in (h,m,s) do (call :drawHand strScr !Hand%%i! %%i !futureTime!)
  37. (call :setPoint strScr 0 0 !PntCenter!)
  38. :testSec
  39. (set datetime=%date:~0,10%%time:~0,8%)&&(set datetime=!datetime: =0!)
  40. (set futureDateTime=!futureDate:~0,10!!futureTime:~0,8!)
  41. if "!datetime!" geq "!futureDateTime!" (goto loop)
  42. rem 当系统时钟向过去调整后, 确保至多在2秒后仍能与系统时钟同步
  43. (set /a past=1!futureTime:~6,2! - 1!datetime:~16,2!) && (set past=!past:-=!)
  44. if "!futureTime:~6,2!" equ "00" if "!datetime:~16,2!" equ "59" (goto testSec)
  45. if !past! gtr 1 (goto loop)
  46. goto testSec
  47. exit /b
  48. rem ========== end of main program =================================================================
  49. :math
  50. set /a "sin0=0,sin6=105,sin12=208,sin18=309,sin24=407,sin30=500,sin36=588,sin42=669,sin48=743,sin54=809,sin60=866,sin66=914,sin72=951,sin78=978,sin84=995,sin90=1000"
  51. for /l %%i in (0, 6, 90) do (
  52.   set /a "a1=180-%%i, a2=180+%%i, a3=360-%%i"
  53.   set /a "sin!a1!=!sin%%i!, sin!a2!=-!sin%%i!, sin!a3!=-!sin%%i!"
  54. )
  55. for /l %%i in (0, 6, 360) do (
  56.   set /a "a4=450-%%i, a4%%=360"
  57.   set /a "cos%%i=sin!a4!"
  58. )
  59. exit /b
  60. rem creatDial Screen !pointDial!
  61. :creatDial
  62. for /l %%x in (!xStart!,-1,!xEnd!) do for /l %%y in (!yStart!,1,!yEnd!) do (
  63.   (set /a inDial=size*size-%%x*%%x-%%y*%%y+1*size) && if !inDial! geq 0 (call :setPoint %1 %%x %%y %2)
  64. )
  65. (call :drawScale %1)
  66. exit /b
  67. rem drawScale Screen
  68. :drawScale
  69. for /l %%z in (0,1,11) do ( rem 标12个刻度
  70.   (set /a angle=%%z+1) && (set /a angle*=30)
  71.   set /a "x=cos!angle!*rScale/sin90, y=sin!angle!*rScale/sin90"
  72.   (set romanNum=!RomanNumbers:~%%z,1!)
  73.   (call :setPoint %1 !x! !y! !romanNum!)
  74. )
  75. exit /b
  76. rem drawHand Screen !HandLength! !HandFlag! !timeNow! [!BlankStr!]
  77. rem 第5个参数 !BlankStr! 是可选的, 当传递了有效的第5个参数时, 将是擦除指针.
  78. :drawHand
  79. (set timeC=%4)
  80. (set timeh=!timeC:~0,2!)&(set timem=!timeC:~3,2!)&(set times=!timeC:~6,2!)
  81. for %%i in (h,m,s) do if !time%%i! lss 10 (set time%%i=!time%%i:~-1!)
  82. set /a "timeh%%=12"
  83. set /a "angleh=30*timeh+(timem+6)/12*6, anglem=6*timem, angles=6*times"
  84. set /a "xE=%2*cos!angle%3!*2/sin90, yE=%2*sin!angle%3!*2/sin90"
  85. if "%5"=="" (call :line %1 0 0 !xE! !yE! %2 !Pnt%3!) else (call :line %1 0 0 !xE! !yE! %2 %5)
  86. exit /b
  87. rem line Screen x1 y1 x2 y2 !LenHand! !PointChr!
  88. :line
  89. (set x0=%2)&(set y0=%3)&(set x1=%4)&(set y1=%5)&(set /a SQLenHand=%6*%6)
  90. set /a "steep=(y1 - y0)*(y1 - y0) - (x1 - x0)*(x1 - x0)"
  91. if !steep! gtr 0 (
  92.   (set tt=!x0!&& set x0=!y0!&& set y0=!tt!)
  93.   (set tt=!x1!&& set x1=!y1!&& set y1=!tt!)
  94. )
  95. if !x0! gtr !x1! (
  96.   (set tt=!x0!&& set x0=!x1!&& set x1=!tt!)
  97.   (set tt=!y0!&& set y0=!y1!&& set y1=!tt!)
  98. )
  99. set /a "deltax=x1-x0, twoDeltax=2*deltax"
  100. set /a "twoDeltay=2*(y1-y0)" && (set twoDeltay=!twoDeltay:-=!)
  101. set /a "eps=0, y=y0"
  102. if !y0! lss !y1! (set yStep=1) else (set yStep=-1)
  103. for /l %%x in (!x0!,1,!x1!) do (
  104.   set /a "SQSum=%%x*%%x+y*y"
  105.   if !SQSum! leq !SQLenHand! (
  106.     if !steep! gtr 0 (call :setPoint %1 !y! %%x %7) else (call :setPoint %1 %%x !y! %7)
  107.   )
  108.   (set /a eps+=twoDeltay)
  109.   if !eps! gtr !deltax! (set /a "y+=yStep, eps-=twoDeltax")
  110. )
  111. exit /b
  112. rem getNextSec futureTime futureDate
  113. :getNextSec
  114. (set time1=!time:~0,-3!)&(set date1=!date!)
  115. (set timeh=!time1:~0,2!)&(set timem=!time1:~3,2!)&(set times=!time1:~6,2!)
  116. (set timeY=!date1:~0,4!)&(set timeMn=!date1:~5,2!)&(set timeD=!date1:~8,2!)&(set timeDay=!date1:~-1!)
  117. for %%i in (h,m,s,Mn,D) do if !time%%i! lss 10 (set time%%i=!time%%i:~-1!)
  118. (set /a "timeS=(timeS+1)%%60")
  119. if !timeS! equ 0 (
  120.   (set /a "timeM=(timeM+1)%%60")
  121.   if !timeM! equ 0 (
  122.     (set /a "timeH=(timeH+1)%%24")
  123.     if !timeH! equ 0 (
  124.       rem 这里不考虑大小月, 平闰月的问题, 将所有月份看作 31 天, 会出现错误的日期, 不能用于显示.
  125.       (set /a "timeD=timeD%%31+1")
  126.       for %%i in (一,二,三,四,五,六,日) do (
  127.         if "%%i"=="!timeDay!" (set nextDay=!days:*%%i=!)&&(set nextDay=!nextDay:~0,1!)
  128.       )
  129.       (set timeDay=!nextDay!)
  130.       if !timeD! equ 1 (
  131.         (set /a "timeMn=timeMn%%12+1")
  132.         if !timeMn! equ 1 (set /a timeY+=1)
  133.       )
  134.     )
  135.   )
  136. )
  137. for %%i in (h,m,s,Mn,D) do if !time%%i! lss 10 (set time%%i=0!time%%i!)
  138. (set %1=!timeH!:!timeM!:!timeS!) & (set %2=!timeY!-!timeMn!-!timeD! 星期!timeDay!)
  139. exit /b
  140. rem setPoint Screen !x! !y! !pointStr!
  141. :setPoint
  142. set /a "index=(xStart-%2)*width+%3-yStart+1"
  143. set /a "lenLeft=index-1, lenRight=indexMax-index"
  144. for /f "tokens=1,2,3" %%a in ("!lenLeft! !index! !lenRight!") do (set %1=!%1:~0,%%a!%4!%1:~%%b,%%c!)
  145. exit /b
复制代码
附件: 您需要登录才可以下载或查看附件。没有帐号?注册

删除了无效的百度相册图片链接(2009-12-13)
5

评分人数

TOP

虽然没能做到每秒刷屏,已经很不错了,我想过做,结果没做出来。
加分!

TOP

原帖由 netbenton 于 2009-12-3 07:52 发表
虽然没能做到每秒刷屏,已经很不错了,我想过做,结果没做出来。
加分!


                                                                                             同上。

刷屏来说,没你那个技术,批处理本身的性质刷全屏,还是不要太频繁好~

[ 本帖最后由 523066680 于 2009-12-3 08:40 编辑 ]

TOP

功力浓厚,代码也书写规范,看来楼主真不是一般人啊,赞一个!
***共同提高***

TOP

楼主的代码写的很规范 看来功夫不浅

TOP

谢谢各位的肯定!  闲来对代码又作了一点小的改良.
(这里是2.11修正版--原2.10版有bug,己被替换,  最后的 2.3 版代码己贴在 1 楼)
2.11修正版代码已作为附件移至 1 楼, 有兴趣者请下载
2.11版采用仅仅对二维表盘缓冲变量 scr 进行: 重绘刻度, 擦除旧时间指针, 重绘新时间指针 来刷新屏幕
而2.0版是对整个表盘擦除, 或用一个无指针的表盘覆盖旧的绘图, 再来重绘(刻度和)指针.
相比之下, 本版刷屏的工作量少了许多, 所以刷屏速度提高不少, 同样在 赛扬单核 2GHz CPU 上, 实现了 1 秒内刷屏, 甚至不是当前窗口.




[ 本帖最后由 neorobin 于 2009-12-13 23:05 编辑 ]

TOP

&&刷屏建议楼主采用临时文件+type来进行,具体参见此贴中10楼的方法:
http://bbs.bathome.net/thread-365-1-1.html
***共同提高***

TOP

模仿双缓存好像做不到。
也许可以用双进程,打开后  一句特殊判断进入: start %0 + 调用指定函数进入处理阶段,
本身进程则用来type文本并显示。
(仅仅是猜想)

[ 本帖最后由 523066680 于 2009-12-3 18:27 编辑 ]

TOP

回复 8楼 的帖子

2.10版作一点小的修改就可试行:
  1. (set strScr=)
  2. for /l %%x in (!xStart!,-1,!xEnd!) do for /l %%y in (!yStart!,1,!yEnd!) do (set strScr=!strScr!!scr_%%x_%%y!)
  3. for %%i in (h,m,s) do (call :drawHand scr !Hand%%i! %%i !timeNow! !PntB!)
  4. cls & (set /p=!strScr!  !Blanks!  !date! !time:~0,-3!  !Blanks!<nul)
复制代码
改为:
  1. (set /p=<nul>fScreen)
  2. for /l %%x in (!xStart!,-1,!xEnd!) do for /l %%y in (!yStart!,1,!yEnd!) do (set /p=!scr_%%x_%%y!<nul>>fScreen)
  3. (set /p=!strScr!  !Blanks!  !date! !time:~0,-3!  !Blanks!<nul>>fScreen)
  4. for %%i in (h,m,s) do (call :drawHand scr !Hand%%i! %%i !timeNow! !PntB!)
  5. cls & (type fScreen)
复制代码
运行后证实,  用 文件+type  比 用内存变量 速度低, 与我预想的一致.
2.10版可在 赛扬单核 2GHz CPU 上实现每秒刷新, 但用 文件+type 的方法在同样 CPU 上有时会超过 1 秒才能刷新.

TOP

^_^ 能想象到一直读写文件对系统比较挑战。

TOP

我来提提速,把图形初始化放在循环外,利用setlocal enabledelayedexpansion和endlocal来恢复变量

分和秒防前导0错误可以这样避免:set/a sec=1!time:~6,2!-100


另外有些地方还可以提速,

1。分针和时针,也可以像秒针一样采用触发绘出
2。以“行”为单位存放图形数据,利用串截取再重组方式来更新显示点,这样可以避免刷屏时对每个点都要用set 来重组一次,并且可以减少变量占用空间和变量的数量

这样改进后,每秒刷5次屏应该都可以。我没有时间搞了,看楼主的吧。



  1. @echo off
  2. msg %username% /time:60 请右键单击时钟窗口标题栏, 选择“属性”-^>“字体”选项卡,“点阵字体”,大小: 6 x 12,以得到更好的显示效果
  3. title 指针时钟 2.0 by neorobin 叶结点
  4. setlocal enabledelayedexpansion
  5. color 9f
  6. set /a "size=19, HandS=size-1, HandM=HandS-4, HandH=HandM-4, rScale=size-1"
  7. set /a "xStart=size, xEnd=-size, yStart=-size, yEnd=size"
  8. set /a "Cols=(size*2+1)*2, Lines=size*2+1+1"
  9. (set PntCenter=◎)&(set PntH=●)&(set PntM=○)&(set PntS=·)&(set PntB=▓)
  10. (set RomanNumbers=ⅠⅡⅢⅣⅤⅥⅦⅧⅨⅩⅪⅫ)
  11. set /a "leftSpaces=(size*2+1-13)/2-2" & (set Blanks=)
  12. for /l %%i in (1,1,!leftSpaces!) do (set Blanks=!PntB!!Blanks!)
  13. mode con cols=!Cols! Lines=!Lines!
  14. call :math
  15. if %time:~6,2% geq 10 (set sec=%time:~6,2%) else (set sec=%time:~7,1%)
  16. (call :clrScr scr !PntB!)
  17. rem 标12个刻度
  18. for /l %%z in (0,1,11) do (
  19.   (set /a angle=%%z+1) && (set /a angle*=30)
  20.   set /a "x=cos!angle!*rScale/factor, y=sin!angle!*rScale/factor"
  21.   set "scr_!x!_!y!=!RomanNumbers:~%%z,1!"
  22. )
  23. :loop
  24. (set sec1=!sec!)
  25. setlocal enabledelayedexpansion
  26. for %%i in (h,m,s) do (call :drawHand !Hand%%i! %%i)
  27. set "scr_0_0=!PntCenter!"
  28. (set strScr=)
  29. for /l %%x in (!xStart!,-1,!xEnd!) do for /l %%y in (!yStart!,1,!yEnd!) do (
  30.   (set strScr=!strScr!!scr_%%x_%%y!)
  31. )
  32. cls&(set /p=!strScr!  !Blanks!  !date! !time:~0,-3!  !Blanks!<NUL)
  33. endlocal
  34. :testSec
  35. ::if %time:~6,2% geq 10 (set sec=%time:~6,2%) else (set sec=%time:~7,1%)
  36. set/a sec=1!time:~6,2!-100&if !sec! neq !sec1! (goto loop) else goto testSec
  37. exit /b
  38. rem ========== end of main program =================================================================
  39. :math
  40. set /a "sin0=0,sin6=105,sin12=208,sin18=309,sin24=407,sin30=500,sin36=588,sin42=669,sin48=743,sin54=809,sin60=866,sin66=914,sin72=951,sin78=978,sin84=995,sin90=1000"
  41. (set /a factor=1000)
  42. for /l %%i in (0, 6, 90) do (
  43.   set /a "a1=180-%%i, a2=180+%%i, a3=360-%%i"
  44.   set /a "sin!a1!=!sin%%i!, sin!a2!=-!sin%%i!, sin!a3!=-!sin%%i!"
  45. )
  46. for /l %%i in (0, 6, 360) do (
  47.   set /a "a4=450-%%i, a4%%=360"
  48.   set /a "cos%%i=sin!a4!"
  49. )
  50. exit /b
  51. rem drawHand !HandLength! !HandFlag!
  52. :drawHand
  53. (set timeh=!time:~0,2!)&(set timem=!time:~3,2!)&(set times=!time:~6,2!)
  54. for %%i in (h,m,s) do if !time%%i! lss 10 (set time%%i=!time%%i:~-1!)
  55. set /a "timeh%%=12"
  56. set /a "angleh=30*timeh+(timem+6)/12*6, anglem=6*timem, angles=6*times"
  57. set /a "xE=%1*cos!angle%2!*2/factor, yE=%1*sin!angle%2!*2/factor"
  58. call :line scr 0 0 !xE! !yE! %1 !Pnt%2!
  59. exit /b
  60. rem clrScr scr !strBlank!
  61. :clrScr
  62. for /l %%x in (!xStart!,-1,!xEnd!) do for /l %%y in (!yStart!,1,!yEnd!) do (
  63.   (set /a inDial=size*size-%%x*%%x-%%y*%%y+1*size)&& if !inDial! geq 0 (set scr_%%x_%%y=!PntB!) else (set scr_%%x_%%y=  )
  64. )
  65. exit /b
  66. rem line scr x1 y1 x2 y2 !LenHand! !PointChr!
  67. :line
  68. (set x0=%2)&(set y0=%3)&(set x1=%4)&(set y1=%5)&(set /a SQLenHand=%6*%6)
  69. set /a "steep=(y1 - y0)*(y1 - y0) - (x1 - x0)*(x1 - x0)"
  70. if !steep! gtr 0 (
  71.   (set tt=!x0!&& set x0=!y0!&& set y0=!tt!)
  72.   (set tt=!x1!&& set x1=!y1!&& set y1=!tt!)
  73. )
  74. if !x0! gtr !x1! (
  75.   (set tt=!x0!&& set x0=!x1!&& set x1=!tt!)
  76.   (set tt=!y0!&& set y0=!y1!&& set y1=!tt!)
  77. )
  78. set /a "deltax=x1-x0, twoDeltax=2*deltax"
  79. set /a "twoDeltay=2*(y1-y0)" && (set twoDeltay=!twoDeltay:-=!)
  80. set /a "eps=0, y=y0"
  81. if !y0! lss !y1! (set yStep=1) else (set yStep=-1)
  82. for /l %%x in (!x0!,1,!x1!) do (
  83.   set /a "SQSum=%%x*%%x+y*y"
  84.   if !SQSum! leq !SQLenHand! (
  85.     if !steep! gtr 0 (set "%~1_!y!_%%x=%7") else (set "%~1_%%x_!y!=%7")
  86.   )
  87.   (set /a eps+=twoDeltay)
  88.   if !eps! gtr !deltax! (set /a "y+=yStep, eps-=twoDeltax")
  89. )
  90. exit /b
复制代码

TOP

回复 11楼 的帖子

好像大家都没怎么注意 我在 7 楼发的 2.10版, 虽说刚刚发现了一个 BUG, 而且已经找到原因并排除了
BUG: 当时数为一位数时, 前面有一个空格, 在参数传递时, 这个空格会被忽略, 或者作为参数分隔, 将一个值中有1个空格的参数从中分隔成了两个参数:
(set timeNow=t!time!) 本意是想保留前面的空格, 避免在参数传递时前面的空格被忽略而不传送到子脚本,
空格是留住了, 却造成将这个参数分成了两个, 最终空格还是造成了错误.
解决方案:
(set timeNow=t!time!) 改为 (set timeNow=!time: =0!) & rem 防止 hour 值小于 10 时造成的参数串长差异错误
drawHand 过程中
(set timeC=%4) && (set timeC=!timeC:t=!) 改为 (set timeC=%4)

12 楼 秋风夜雨 提到的
1. set/a sec=1!time:~6,2!-100 确实是一个好巧妙的方法, +100-100 抵消了, 但用算术性去掉了前面的 0

2. 分针和时针也采用有条件更新的话, 实现上有些复杂, 这得考虑三个指针之间的角度, 两个指针的夹角>90°才完全没有相互遮盖的问题, 一个指针重绘了, 那么和它有遮盖关系的指针也得重绘部分或全部, 这样算法会很复杂.  而事实上, 画这些指针的循环只是从中心到两倍的指针长处拉线段, 这个运算量并不很大, CPU 耗时应是可以忽略的.

3. 和仁兄一样, 其实我最初想到的方法(1.0版)就是直接在一个一维串上绘图, 但旧版的配合算法很低效; 于是2.0版考虑了先在二维数组上缓存绘图, 如果有好的一维串操作方法, 省去这个二维变量组确实是很理想的, 我在考虑这个方案.

TOP

楼主,7楼代码不正常,请检查一下。

一维串操作,设x为行,y为列,
set /a y0=y-1
for /f "tokens=1,2,3" %%x in ("!x! !y! !y0!") do (
    set line%%x=!line%%x:~,%%z!点!line%%x:~%%y!
)


另外,如果附件和贴出来的代码是一样的话,请不要上传附件,以节约论坛空间。谢谢配合。

TOP

回复 14楼 的帖子

7楼的问题已经在 13 楼说明了, 这里补发一下修正的 2.11 完整代码(2.11修正版代码已转移到 1 楼, 代码和打包附件)

[ 本帖最后由 neorobin 于 2009-12-13 22:55 编辑 ]

TOP

返回列表