标题: [分享]批处理多行回退(规律讨论篇) [打印本页]
作者: batman 时间: 2011-3-1 23:09 标题: [分享]批处理多行回退(规律讨论篇)
全文由本人同步发表在个人qq空间:http://user.qzone.qq.com/841615149/infocenter
还记得刚刚接触批处理时很喜欢写特效,看着自己编写的代码在dos窗口中变成一幅幅跳动的画面时,心里那个成就感啊。。。可是,慢慢就发现用批写特效真的是很费劲,受到的限制太多了。其中最受不了的就是动画的实现基本靠cls刷屏重输出,整个画面闪动的厉害,一点都不连贯,这些都是因为dos的逐行输出性质决定的。但值得庆幸的是微软总算还是创造了一个神奇的退格符“”,用它和空格组合可以将最后行进行重输出而不用cls来刷屏,如下代码:- @echo off&setlocal enabledelayedexpansion
- set "str= 我在向不断向左移动哦"
- for /l %%a in (1,1,24) do set "t=!t! "
- echo 请注意下面文字的变化&echo.&set /p===^><nul
- :lp
- for /l %%a in (1,1,11) do (
- set /a a=6*%%a
- for %%b in (!a!) do set "t1=!t:~%%b!"
- set /p=!str:~%%a!<nul
- for /l %%b in (1,1,2000) do echo>nul
- set /p=!t1!<nul
- )
- goto lp
复制代码
画面总算不闪而且流畅了,这都是神奇的“”的功劳啊。那么它是怎么实现这一效果的呢?“”的学名叫做退格符,但它这个退格是将光标(即输出点)退回一格,请记住它并不会删除前面的输出内容。但它和空格的组合“ ”就能成功将前一格的内容删除并将光标回退一格(大家想一想为什么能够实现)。在这里,我还要提醒大家退格每次只回退一个字节的距离,这个距离相当于单字节字符(数字、字母、字符)的宽度以及双字节字符(汉字、标点)的一半宽度。所以我们只要知道要回退删除的距离为n(以单字节计算),就可以用n个“ ”组合来实现精确的回退删除,如果要重输出整行,我们就可以采用足够多的“ ”组合来实现(而不用知道要回退的距离)。但是这种方法仅仅只能对末行进行重输出,如果要对末行以上的行进行重输出就只能用cls刷屏重输出了。当然,我们还可以用将一帧帧的画面先输出到临时文本中,cls后再用type对临时文本进行输出,如此来实现对画面的重写,而这个要比单单cls刷屏重写要显得流畅些(因为无论是多少内容,type都是一次性输出):- @echo off&setlocal enabledelayedexpansion
- set "str=我是一帧帧的画面,连贯起来就成了动画"
- for /l %%a in (0,1,17) do (
- echo !str:~%%a,1!>tmp
- type tmp
- for /l %%b in (1,1,2000) do echo>nul
- cls
- )
- del /q tmp&pause
复制代码
但是,当输出的内容很多时,用type方法效率上就有问题了。而且很多时候我们仅仅是对画面的局部进行变化,如果每次要输出整个画面确实是一种效率上的浪费(个人认为)。那么,还有没有别的办法来实现对画面局部变化呢?前面我特意提到神奇的“”,如果仅仅局限在一行内实现回退是称不上神奇的。那么它真正的神奇之处在哪里呢?一个偶然的机会,本人发现用echo输出一个tab+n个退格符就能将光标回退到原点,注意这个n是足够多,本人当时取的是1000,就在论坛发表了以下代码:- @echo off&setlocal enabledelayedexpansion
- :: 灵感来源于cn-dos趣味东的多行回退
- :: 趣味东发现用set /p输出一个tab+n个退格就将光标回退多行,但并不好控制
- :: 于是本人就想到是不是能将光标回退到原点(屏幕左上角)
- :: 结果发现用echo输出一个tab+n个退格就能将光标退回到原点过一格的位置,但有错误信息输出
- :: 于是,用2>nul屏蔽错误信息,并再加一个退格将光标退回原点
- :: 下面通过代码进行简单演示,至于原因本人暂未搞明白
- ::请将下面的tab换成实际的制表符
- set "t=tab"
- title 神奇的回退
- for /l %%a in (1,1,1000) do set "k=!k!"
- for /l %%a in (1,1,10) do echo ○○○○○○○○○○
- ping /n 2 127.1>nul
- :: 这里将光标退回原点处,请仔细注意光标的位置
- echo %t%%k% 2>nul&set /p=<NUL
- pause>nul
- :: 请注意6-10行第6-10个字符的输出是没有改变的
- for /l %%a in (1,1,5) do echo ●●●●●¤¤¤¤¤
- for /l %%a in (1,1,5) do echo ⊙⊙⊙⊙⊙
- pause>nul
复制代码
这确实是一个重大的突破,但是按这个方法将光标退回到原点后再用echo,方法可以将光标重定位到要修改的行的行首(仅能到定位到行首),就能方便地实现画面的局部修改。但本人在一次测试时(当时是输出的150行)发现光标没有按计划退到原点,而是只是回退了99行。这下看来这个光标回退行是有规律的,于是,本人写下了下面的测试代码来寻找这一规律(当时猜想应该是个10*行+n的规律):- @echo off&setlocal enabledelayedexpansion
- ::请将下面的tab换成实际的制表符
- set "t=tab"
- for /l %%a in (1,1,210) do (
- set "k=!k!"&cls
- for /l %%b in (1,1,20) do (
- for /l %%c in (1,1,20) do set "str=!str!■"
- echo !str!&set "str="
- )
- 2>nul echo %t%!k!
- echo %%a
- for /l %%b in (1,1,1000) do echo>nul
- )
- pause>nul
复制代码
通过这个测试,终于得出了计算公式,退格符的个数=要回退的行(含空行)*10+2。如此以来,我们就掌握了回退行的规律了,通过与echo,的配合就能随时实现光标的上上下下了(当然指在行首)哈哈,下面就小写一段特效用以“自诩”_|_":- @echo off&setlocal enabledelayedexpansion
- mode con cols=50 lines=12&color 9f
- ::请将下面的tab换成实际的制表符
- set "t=tab"
- for /l %%a in (1,1,11) do (
- set /p= *<nul
- for %%b in (1 11) do if %%a equ %%b set "flag=a"
- if defined flag (
- for /l %%b in (1,1,39) do set /p=*<nul
- set "flag="
- ) else (
- if %%a equ 6 (
- set /p= 无 为 *<nul
- ) else (
- for /l %%b in (1,1,38) do set /p= <nul
- set /p=*<nul
- )
- )
- echo.
- )
- for /l %%a in (1,1,52) do set "k=!k!"
- 2>nul echo,%t%!k!&set "k=!k:~30!"
- for /f "tokens=3 delims=:" %%a in (%~0) do (
- set /a n+=1,m=n%%2
- set /p= *<nul
- for /l %%b in (1,1,12) do set /p= <nul
- set /p=%%a<nul
- for /l %%b in (1,1,2000) do echo>nul
- if !m! equ 0 (
- 2>nul echo,%t%%k%
- ) else (
- echo,&echo,
- )
- )
- for /l %%b in (1,1,2000) do echo>nul
- 2>nul echo,%t%%k%
- echo * 无 为
- for /f "tokens=3 delims=:" %%a in (%~0) do echo * %%a
- pause>nul
- ::#:#:光阴无声逝如风
- ::#:#:一梦醒觉行囊空
- ::#:#:可叹寒窗十年问
- ::#:#:不入尘缘竟峥嵘
- ::#:#:遥想子成家业时
- ::#:#:情迷书墨一老翁
复制代码
小诗也是自己乱写的,代码也没有简化,权当好玩了,呵呵。
【扩展资料】
探讨:ECHO;TAB若干退格字符将光标多行回退与窗口列宽的关系
http://bbs.bathome.net/thread-41792-1-1.html
作者: wc726842270 时间: 2011-3-2 08:46
版主的代码也让我明白了CMD是以16进制—双字节读取内容的。刚才试过保存为UTF—8和用ASC||字符(在ANSI的情况下应该用0补位了吧,所以也是2个字节),在退格符处理ANSI中的字符时有点小意外,不过这好像是处理补位的结果吧。不过还是希望有个明确的答案
是不是因为补位会被过滤啊,现在还仅仅是个猜测
[ 本帖最后由 wc726842270 于 2011-3-2 08:55 编辑 ]
作者: cjiabing 时间: 2011-3-2 10:00
batman 是个人才,谢谢分享,终于有人肯下功夫来研究这一特效了,这个功能将极大地促进批处理动画的发展,期待中!~
作者: Batcher 时间: 2014-12-26 16:41
test-1.bat 退格符直接写在脚本里面- @echo off
- echo bbs.bathome.net
- set /p =光标回退(非cls清屏)动画效果演示:<nul
- for /l %%i in (1,1,10) do (
- set /p =%%i<nul
- set /p =<nul
- ping -n 2 127.1 >nul
- )
- echo,
- pause
复制代码
test-2.bat 用命令生成退格符- @echo off
- echo bbs.bathome.net
- for /f %%i in ('echo prompt $H ^| cmd') do (
- set "KeyBS=%%i"
- )
- set /p =光标回退(非cls清屏)动画效果演示:<nul
- for /l %%i in (1,1,10) do (
- set /p =%%i<nul
- set /p =%KeyBS%<nul
- ping -n 2 127.1 >nul
- )
- echo,
- pause
复制代码
test-3.bat 倒计时+不换行+空格开头- @echo off
- echo bbs.bathome.net
- for /f %%i in ('echo prompt $H ^| cmd') do (
- set "KeyBS=%%i"
- )
- echo 倒计时:
- for /l %%i in (9,-1,1) do (
- set /p "= %KeyBS% %%i"<nul
- set /p "=%KeyBS%%KeyBS%%KeyBS%"<nul
- timeout /t 1 >nul
- )
- echo,
- echo 执行完毕
- pause
复制代码
作者: 老刘1号 时间: 2017-4-9 10:28
这么6的帖子没人顶不科学啊
作者: 1055367558 时间: 2017-9-24 10:47
诶呦,不错啊。。以前还不知道怎么用- @echo off
- set /p =光标回退显示时间(非cls清屏):<nul
- :a
- set/p =%time:~0,8%<nul
- for /l %%k in (1,1,8) do (set/p=<nul)
- ping -n 1 127.1 >nul
- goto a
复制代码
作者: yyz219 时间: 2021-10-22 09:20
回复 5# 老刘1号
确实很强大。学习学习
作者: hnfeng 时间: 2023-3-14 11:30
厉害,强大啊
作者: dos-a 时间: 2023-4-3 19:53
回复 1# batman
现在win10上无法实现多行回退啊
欢迎光临 批处理之家 (http://bathome.net./) |
Powered by Discuz! 7.2 |