主题:C A I程式设计DOS QB篇
[url=http://m2.ssps.tpc.edu.tw/~shey/cait0.htm]C A I程式设计DOS QB篇[/url]
对QB编程很有帮助,只是用繁体写的
不过我已经把这些网页翻译为GB格式的,放到 qbasic45@163.com pw:11111111
另外不知是谁把qbasic45@163.com中原有的邮件都删了!!!(恶毒)
下面是其中的部分内容
第五章 键盘扫描
在 CAI 中,由键盘输入资料, 是常用的方法,特别是对於一些年幼
的小朋友、初次接触电脑者,他们跟本无法很称心的操控滑鼠,因此
,键盘就更显得其重要性。
5-1 键盘扫描
当程式执行到需要使用者输入答案时,整个程式是停下来,等待使用
者输入资料吗?表面上,看起来是停下来等待使用者输入资料,事实
上,程式并没有停下来,它不断的在扫描使用者的反应,这些反应可
能根本不是内定要使用者输入的答案,而电脑都需要马上知道并做处
理, 如按了 ESC 键、按错键了、按求助键等。在待答这段时间内,
电脑本身也有许多是要处理。如计时、显示时间、背景音乐等。等待
输入答案,反而变成整个待答过程中的一小部份。
QB 提供了四种输入的指令:
INPUT
LINE INPUT
INPUT$
INKEY$
我们不介绍前面叁种指令,仅介绍 INKEY$,INKEY$ 函数与前面叁种
输入方法有很大的差异,特别是要做到前面所说的如待答计时等,非
得用到 INKEY$ 函数不可。 INKEY$ 函数可以模拟成 INPUT、 LINE
INPUT、 INPUT$ 等函数的功能。 但是要用 INPUT、 LINE INPUT、
INPUT$ 等函数来完成一个待答过程的副程式,那就困难多了。
1.INKEY$ 指令介绍
【程式5-1】
1 '5-1
2 CLS
3 DO
4 LOCATE 1, 1
5 PRINT TIME$
6 A$ = INKEY$
7 LOOP UNTIL A$ <> ""
8 PRINT A$, ASC(A$)
9 END
说明:
(1) 等待按键,同时显示时间,若按任一键则离开回路, 并印出
所按键及 ASCII 值。
(2) 这个程式执行时,只能输入一个字元。 因此, INKEY$ 函数
用在控制程式,是一个很好的函式。 如果要利用 INKEY$ 来
输入一串资料,就需要花点功夫,来写个输入副程式了。
(3) 用 INKEY$ 来控制程式时, 是不需要把使用者输入的按键显
示出来的,同时有些按键是无法在萤光幕上显示出来的。 所
以,用内码 ASCII 码,是经常使用的方法。可以把程式 5-1
改成按 Enter 键结束。
CLS
DO
LOCATE 1, 1
PRINT TIME$
A$ = INKEY$
LOOP UNTIL A$ = CHR$(13)
PRINT A$, ASC(A$)
END
2.常用按键的内码
(1) 哪些按键是程式中经常要用到的呢?它们的内码又是什麽?
如何扫描得到呢?在 CAI 中最常用到的键有:Enter、Spc、
Esc、↑、↓、→、←、PgUp、PgDn、F1 等。
(2) 各按键所代表的意义是什麽?
国内 CAI 经过这几年的推广, 在按键功能已经有一共同的默
契了!因此, 在 CAI 按键功能设定时不可与与一般使用者的
的习惯相左,而独树一格,造成使用者的不便。
Enter :确定、选择游标处的选项。
Spc :跟 Enter 键相同意义。
Esc :离开、结束、不玩了、回目录、取消。
↑↓→← :游标向上、下、左、右移动。
PgUp :向上一页。
PgDn :向下一页。
F1 :表示求助、请求帮助、给一些提示。
数字键 :表示选项、选目、输入答案。
(3) 如何扫描得到呢?
用程式 5-1 能扫描到上面几个按键吗? 有些键是可以扫描到
内码的,如 Enter 键内码是 13、Esc 键是 27、空白键是 32
。 其他的像↑、↓、→、←、PgUp、PgDn、F1 等的内码又是
如何呢?这些键用程式 5-1 所侦测到的内码都是 0, 但是萤
光幕上却显示出一些字元。内码值与萤光幕所显示字元的内码
值不一样,主要是因为这几个键是属於扩充键,当程式扫描到
扩充键时,会传回两个码,扩充码的第一个码是 0,第二个码
才是这个键的码, 所以用程式 5-1 是扫描不到这些扩充码的
。
【程式 5-2 】
1'5-2
2 CLS
3 DO
4 LOCATE 1, 1
5 PRINT TIME$
6 A$ = INKEY$
7 LOOP UNTIL A$ <> ""
8 IF LEN(A$)=2 THEN A$ = RIGHT$(A$,1)
9 KEYCODE = ASC(A$,1)
10 PRINT KEYCODE
11 END
说明:程式加了第八行, 判断是否按了扩充键,若是扩充键则取
其第二个字元。
(4) 重要按键的内码值
Enter:13 F1 :扩充码 59
Spc :32 F2 :扩充码 60
Esc :27 .
↑ :扩充码 72 .
↓ :扩充码 80 F10 :扩充码 68
→ :扩充码 77 Ins :扩充码 82
← :扩充码 75 Del :扩充码 83
PgUp :扩充码 73 Home:扩充码 71
PgDn :扩充码 81 End :扩充码 79
一些组合键也可以扫描到。如下:
Ctrl-Enter:扩充码 10
Ctrl-Spc :扩充码 32
Ctrl-F1 :扩充码 94
其馀的内码可以参考内码表。
(5) 如何克服扩充码与正常码冲突的问题?
为了程式上的方便,通常把扩充码的值加上负号,这样在程式
上就非常好辨认。
【程式5-3】
1 '5-3
2 CLS
3 DO
4 LOCATE 1, 1
5 PRINT TIME$
6 A$ = INKEY$
7 LOOP UNTIL A$ <> ""
8 IF LEN(A$)=2 THEN
9 KEYCODE= -ASC( RIGHT$(A$,1))
10 ELSE
11 KEYCODE = ASC(A$,1)
12 END IF
13 PRINT KEYCODE
14 END
说明:程式#8 ~#11 判断是否按了扩充键,若是扩充键则取其第
二个字元,并将扫描码加上负号。
3.计时器
计时在 CAI 中是经常用到的。 如待答时间、观看教学画面、特别
是在游戏式的 CAI 中用的更多。
【程式5-4】
1 '5-4
2 DEFTIME = 10
3 START = TIMER
4 DO
5 IF TIMER - STARTIME > 1 THEN
6 DEFTIME = DEFTIME -1
7 STARTIME = TIMER
8 LOCATE 10 ,40 : PRINT DEFTIME
9 END IF
10 LOOP UNTILL DEFTIME = 0
11 PRINT "TIMER IS VVER !"
12 END
说明:倒数计时十秒钟,每隔一秒钟显示所剩秒数。这个程式在到
数计时过程中,程式只有计时功能,并没有扫描使用者的按
键。
【程式5-5】
1 '5-5
2 DEFTIME=10
3 STARTIME = TIMER
4 DO
5 IN$ = INKEY$
6 IF TIMER - STARTIME > 1 THEN
7 DEFTIME = DEFTIME -1
8 STARTIME = TIMER
9 PRINT DEFTIME
10 END IF
11 LOOP UNTIL IN$ <> "" OR IN$ <> ""
12 IF DEFTIME = 0 THEN
13 PRINT "TIME IS OVER !"
14 ELSE
15 IF LEN(IN$) = 2 THEN
16 KEYCODE = ASC(MID$(IN$,2,1))
17 ELSE
18 KEYCODE = ASC(IN$)
19 END IF
20 PRINT "KEYCODE IS "; KEYCODE
21 END IF
说明:(1) 这个程式可以倒数计时, 同时也侦测使用者的按键,
使用者按任意键, 程式结束,并显示所剩馀时间及按
键内码值。
(2) #4 行到 #11 行,为一回路, 终止条件是按任一键或
计时终了。 在这回路中,一直在做两件事,键盘扫描
、倒数计时。
(3) #12 行到 #21 行,判断按键或计时终了,若计时终了
(#16) 则显示 " TIME IS OVER! "; #14 到 #20,处
理按键的内码值, #13 扩充键的处理,#18 一般按键
内码值处理。 #21 显示出按键内码值。
5-2 音乐开关
很多软体,按 S 键可以控制声音的有无,S 键就如声音的开关。 我
们先看几个简单的程式。
【程式5-6】
1 '5-6
2 DO
3 IN$ = INKEY$
4 S% = RND * 5000 + 200
5 SOUND S%, 0.5
6 LOOP UNTIL IN$ <> ""
说明:随机发出一频率从 200 至 5200 音长为 0.5 的音来。按任一
键程式结束。在回路中程式做叁件事,扫描键盘、取乱数、发
音。
【程式5-7】
1 '5-7
2 ONOFF$ = "ON"
3 DO
4 DO
5 IN$ = UCASE$(INKEY$)
6 IF ONOFF$ = "ON" THEN
7 S% = RND * 5000 + 200
8 SOUND S%, 0.5
9 END IF
10 LOOP UNTIL IN$ = "S"
11 SELECT CASE ONOFF$
12 CASE "ON"
13 ONOFF$ = "OFF"
14 CASE "OFF"
15 ONOFF$ = "ON"
16 END SELECT
17 LOOP UNTIL IN$ = CHR$(27)
说明:(1) 程式 5-7 按 S 键,可以控制声音的有无。
(2) 变数说明 ONOFF$ 开关,初值为"ON",表示"开"。
"OFF" 表示关。
(3) #3 行:UCASE$ 函数会将输入的字元转换成大写, 如此,
就不需要在程式中再检查大小写。 英文字母大小写分别是
不同的内码。如大写 A 内码是 65,小写 a 是 97。
IN$ = UCASE$(INKEY$)
IN$ 所扫描到的英文字母都是大写的。
(4) #11 ~ #16,双向开关设定。 所谓双向开关就如公寓之楼
梯灯开关,若灯开着,按下开关,灯就会息掉; 若灯未开
,按此开关,灯就会开。同理,若有音乐,按下 S 键,音
乐就关掉;若无音乐,按下 S 键,音乐就开了。
用程式语言表示:
IF ONOFF$ = "ON" THEN ONOFF$ = "OFF" ELSE
ONOFF$="ON"
程式 5-7 的 #11 ~ #16 行也是一样。
SELECT CASE
ONOFF$
CASE "ON"
ONOFF$ = "OFF"
CASE "OFF"
ONOFF$ = "ON"
END SELECT
ONOFF$ 变数需配合 #6 ~ #9 行,来控制声音有无。也可
以用程式 5-8 的方法来控制声音的开与关。
【程式5-8】
1 '5-8
2 ONOFF% = 1
3 DO
4 DO
5 IN$ = UCASE$(INKEY$)
6 S% = RND * 5000 + 200
7 SOUND S%, 0.5 * ONOFF%
8 LOOP UNTIL IN$ = "S"
9 SELECT CASE ONOFF%
10 CASE 1
11 ONOFF% = 0
12 CASE 0
13 ONOFF% = 1
14 END SELECT
15 LOOP UNTIL IN$ = CHR$(27)
说明:(1) 这个程式与 5-7 架构雷同, 不同处是程式 5-8 用变数
ONOFF 为数字变数,这个 ONOFF 变数不但是开关也控制着
音长。 当 ONOFF% = 1 则 SOUND S%, 0.5 * ONOFF% 音长
是 0.5 * ONOFF% 等於 0.5。 当变数 ONOFF% = 0 时音长
是 0.5 * ONOFF% 等於 0,所以不发声,没有音乐。
(2) 这种方法与 SOUND 指令配合, 效果相当好。 但是若用
PLAY 指令则用程式 5-7 的方法比较好。
【程式5-9】
'5-9
SOU% = 1
DO
IN$ = UCASE$(INKEY$)
LOCATE 1, 1 : PRINT TIME$
SELECT CASE IN$
CASE "S"
SELECT CASE SOU%
CASE 1
PRINT "SOUND IS OFF !"
SOU%=0
CASE 0
PRINT "SOUND IS ON !"
SOU%=1
END SELECT
END SELECT
PIC% = RND * 5000 + 200
SOUND PIC%, 0.5 * SOU%
LOOP UNTIL I$ = CHR$(27)
END
说明:(1) 这个程式与 5-8 执行的结果完全一样。但是程式的架构却
不一样,这个程式把声音的开关放在回路里面。
(2) 如果要加上倒数计时,并同时发声要如何设计呢?
5-3 背景音乐
所谓背景音乐的意思就是,有画面、有声音。当然这个画面不是静态
的。
【程式5-10】
'5-10
SOU% = 1
DO
IN$ = UCASE$(INKEY$)
LOCATE 1, 1 : PRINT TIME$
SELECT CASE IN$
CASE "S"
SELECT CASE SOU%
CASE 1
PRINT "SOUND IS OFF !"
SOU%=0
CASE 0
PRINT "SOUND IS ON !"
SOU%=1
END SELECT
END SELECT
PIT% = RND * 5000 + 200
SOUND PIT%, 0.5 * SOU%
X% = RND * 639
Y% = RND * 348
CLOR% = RND * 15
PSET (X%, Y%), COLR%
LOOP UNTIL I$ = CHR$(27)
END
说明:(1) 这个程式执行後萤光幕会有满天星、 并有声音出现、同时
显示时间、并扫描键盘。如果按 S 键,声音关掉,并显示
"SOUND OFF!",
(2) 前面几个例子,都是关於音效方面的,用 SOUND 指令来编
一首歌曲,可以用 READ DATA 的方法,比较起来仍然是没
有效率的。
【程式5-11】
1 '5-11
2 CLS
3 PLAY "MB"
4 DO
5 LOCATE 1, 1
6 PRINT "NUMBER OF NOTES LEFT TO PLAY:";
7 IF PLAY(1) < 3 THEN
8 PLAY "O3CDEFGAB>C"
9 END IF
10 PRINT PLAY(1)
11 LOOP UNTIL INKEY$ <> ""
说明:(1) 这个程式利用 PLAY 函数知道缓冲区中还剩下多少音符。
(2) #7 行表示如果缓冲区中的音符小於 3,则重新执行 #8 行
PLAY。如此缓冲区一直都有音符,音乐就不会终止。
(3) #10 行是把缓冲区中还剩下的音符数印出来。
【程式5-12】
1 '5-12
2 SCREEN 9 :CLS
3 DIM SOU$(7)
4 SOU$(1) = "O3L8GL16ECE"
5 SOU$(2) = "L8DL16GFC "
6 SOU$(3) = "O3CEG>C"
7 SOU$(4) = "C 7 THEN I% = 1
20 PLAY "X" + VARPTR$(SOU$(I%))
21 END IF
22 LOOP UNTIL INKEY$ <> ""
说明:(1) 执行这个程式萤光幕会呈现放射状的直线,还有反覆不断
的音乐。按任一键程式结束。
(2) #2 设定绘图页,用模式 9。
(3) #3 定义一个 SOU$音乐阵列。
(4) #4~#10 设定音乐阵列中的音乐资料。
(5) #12~#22 是一个回路,按任一键程式终止。
(6) #13 取一整数乱数X%, 围 0~639 。
#14 取一整数乱数Y%, 围 0~348 。
#15 取一整数乱数COLR%, 围 0~15。
#16 依所取之 X%、Y%、COLR% 之值,用 COLR% 颜色,从
座标 (320, 174), 萤光幕中心位置画一条线到座标
(X%,Y%)。
(7) #17 ~ #21 判断缓冲区中的音符资料是否小於 3, 如果
小馀 3,则执行 #18 ~ #20 行,设定缓冲区中的音符资
料,#18 #19 行是做音乐阵列的检查, 当 I>7 时,表示
乐曲结束,重新设定 I=1, 音乐又重新开始。 如此反覆
#13 ~ #22,直到按任一键,程式才终止。
【程式5-13】
1 '5-13
2 SCREEN 9: CLS
3 SOU$(1) = "O3L8GL16ECE"
4 SOU$(2) = "L8DL16GFC "
5 SOU$(3) = "O3CEG>C"
6 SOU$(4) = "C 7 THEN I = 1
40 PLAY "X" + VARPTR$(SOU$(I))
41 RETURN
说明:(1) 这个程式执行的结果与程式 5-12 相同,但是多了一个音
乐的开关。
(2) #19 ON PLAY(3) GOSUB replay, 当缓冲区中的音符资料
小於 3 时则 GOSUB replay,replay 是一个副程式, 控
制缓冲区中的音符资料内容,让音乐不断反覆。
(3) #24 ~ #34 又是一种控制音乐开关的方法, 这种方法需
配合 PLAY ON 来使用。
6-4 BSAVE 指令介绍
BSAVE 指令主要是将阵列中的资料,存到磁片中的档案。如果阵列中
的资料是图形资料,就如同将图形存起来一样。
【程式6-6】
1 '6-6
2 SCREEN 3,, 1, 1
3 DIM PIC%(38)
4 LINE (12,0)-(0,12)
5 LINE (12,0)-(23,12)
6 LINE (5,9)-(19,23),1,B
7 LINE (5,9)-(19,9),0
8 GET (0,0)-(23,23),PIC%
9 DEF SEG = VARSEG(PIC%(0))
10 BSAVE "PIC1.BLD", VARPTR(PIC%(0)),76
11 DEF SEG
12 END
说明:(1) 这个程式是将阵列 PIC% 以档名 "PIC1 .BLD" 存入。而
阵列 PIC% 内资料为 #4 行至 #7 行所画的房子。
(2) #8 行,捉取图形资料。
(3) #9 行,DEF SEG = VARSEG(PIC%(0)) 定义记忆体区段起
始位置。区段起始位置是阵列 PIC% 第 0 个阵列的位置
。 VARSEG 函式是传回变数所在的区段位址。
(4) #10 行, BSAVE "PIC1.BLD", VARPTR(PIC%(0)), 76
VARPTR 函式是传回变数所指区段位址的节内位址。这个
函式在 PLAY 中经常用到。从 PIC%(0) 的位置开始存76
个 BYTE 长度的资料到档案 PIC1.BLD 中。
(5) QB 对记忆体的应用,分成两个区域:内定资料区段:受
64K 限制。远程推积区段:不受 64K 限制。可用动态阵
列、 或经过 REM $DYNAMIC 宣告的静态阵列都可使用到
本区。
6-5 BLOAD 指令介绍
BSAVE 指令须有 BLOAD 指令来配合, 这两个指令,是直接对记忆体
做存取的动作,其速度是相当的快,是非常有效率的两个指令。
【程式6-7】
1 '6-7
2 SCREEN 3,, 1, 1
3 DIM PIC%(38)
9 DEF SEG = VARSEG(PIC%(0))
10 BLOAD "PIC.BLD", VARPTR(PIC%(0))
11 DEF SEG
12 FOR X = 1 TO 680 STEP 50
13 FOR Y=1 TO 300 STEP 50
14 PUT (X,Y),PIC%,PSET
15 NEXT
16 NEXT
17 END
说明:(1) 这个程式是将程式 6-6 所存的图形资料, 载入记忆体中
,并将图形显示出来。
(2) #3 行,定义图形阵列大小。
(3) #4 行,定义区段位址是从阵列第0个开始。
(4) #10 将图形资料档,直接载入到所指定的记忆体位址中。
即阵列第 0 个位置。
(5) #12至#16 将图形显示出来。
(6) 对於图形阵列大小如何得知?在 #3 行,定义阵列大小,
是因为在程式 6-6 中已经得知。 如果档案很多时,要如
何得知呢?请看程式 6-8 。
【程式6-8】
1 '6-8
2 SCREEN 3,, 0, 1
3 OPEN "I", #1, "PIC.BLD"
4 NUMBYTE= LOF(1)
5 CLOSE #1
6 DIM PIC%(NUMBYTE/2)
7 DEF SEG = VARSEG(PIC%(0))
8 BLOAD "PIC.BLD", VARPTR(PIC%(0))
9 DEF SEG
10 FOR X = 1 TO 680 STEP 50
11 FOR Y=1 TO 300 STEP 50
12 PUT (X,Y),PIC%,PSET
13 NEXT
14 NEXT
15 SLEEP
16 SCREEN 3,,0,0
17 END
说明:(1) 这个程式和程式6-7 执行的结果一样。
(2) #2 设定画图页是第0页,显示页是第一页。
(3) #3至#5,侦测档案大小。LOF(1)传回该档案的大小。
(4) 利用侦测到的档案大小,定义阵列大小。 由於所使用的
为整数阵列, 整数阵列每一个阵列为 2 个 BYTE,因此
,只需要一半的阵列数即可。
(5) #10至#14,在绘图页(背景页)显示图像。
(6) 切换显示页为第0页。
对QB编程很有帮助,只是用繁体写的
不过我已经把这些网页翻译为GB格式的,放到 qbasic45@163.com pw:11111111
另外不知是谁把qbasic45@163.com中原有的邮件都删了!!!(恶毒)
下面是其中的部分内容
第五章 键盘扫描
在 CAI 中,由键盘输入资料, 是常用的方法,特别是对於一些年幼
的小朋友、初次接触电脑者,他们跟本无法很称心的操控滑鼠,因此
,键盘就更显得其重要性。
5-1 键盘扫描
当程式执行到需要使用者输入答案时,整个程式是停下来,等待使用
者输入资料吗?表面上,看起来是停下来等待使用者输入资料,事实
上,程式并没有停下来,它不断的在扫描使用者的反应,这些反应可
能根本不是内定要使用者输入的答案,而电脑都需要马上知道并做处
理, 如按了 ESC 键、按错键了、按求助键等。在待答这段时间内,
电脑本身也有许多是要处理。如计时、显示时间、背景音乐等。等待
输入答案,反而变成整个待答过程中的一小部份。
QB 提供了四种输入的指令:
INPUT
LINE INPUT
INPUT$
INKEY$
我们不介绍前面叁种指令,仅介绍 INKEY$,INKEY$ 函数与前面叁种
输入方法有很大的差异,特别是要做到前面所说的如待答计时等,非
得用到 INKEY$ 函数不可。 INKEY$ 函数可以模拟成 INPUT、 LINE
INPUT、 INPUT$ 等函数的功能。 但是要用 INPUT、 LINE INPUT、
INPUT$ 等函数来完成一个待答过程的副程式,那就困难多了。
1.INKEY$ 指令介绍
【程式5-1】
1 '5-1
2 CLS
3 DO
4 LOCATE 1, 1
5 PRINT TIME$
6 A$ = INKEY$
7 LOOP UNTIL A$ <> ""
8 PRINT A$, ASC(A$)
9 END
说明:
(1) 等待按键,同时显示时间,若按任一键则离开回路, 并印出
所按键及 ASCII 值。
(2) 这个程式执行时,只能输入一个字元。 因此, INKEY$ 函数
用在控制程式,是一个很好的函式。 如果要利用 INKEY$ 来
输入一串资料,就需要花点功夫,来写个输入副程式了。
(3) 用 INKEY$ 来控制程式时, 是不需要把使用者输入的按键显
示出来的,同时有些按键是无法在萤光幕上显示出来的。 所
以,用内码 ASCII 码,是经常使用的方法。可以把程式 5-1
改成按 Enter 键结束。
CLS
DO
LOCATE 1, 1
PRINT TIME$
A$ = INKEY$
LOOP UNTIL A$ = CHR$(13)
PRINT A$, ASC(A$)
END
2.常用按键的内码
(1) 哪些按键是程式中经常要用到的呢?它们的内码又是什麽?
如何扫描得到呢?在 CAI 中最常用到的键有:Enter、Spc、
Esc、↑、↓、→、←、PgUp、PgDn、F1 等。
(2) 各按键所代表的意义是什麽?
国内 CAI 经过这几年的推广, 在按键功能已经有一共同的默
契了!因此, 在 CAI 按键功能设定时不可与与一般使用者的
的习惯相左,而独树一格,造成使用者的不便。
Enter :确定、选择游标处的选项。
Spc :跟 Enter 键相同意义。
Esc :离开、结束、不玩了、回目录、取消。
↑↓→← :游标向上、下、左、右移动。
PgUp :向上一页。
PgDn :向下一页。
F1 :表示求助、请求帮助、给一些提示。
数字键 :表示选项、选目、输入答案。
(3) 如何扫描得到呢?
用程式 5-1 能扫描到上面几个按键吗? 有些键是可以扫描到
内码的,如 Enter 键内码是 13、Esc 键是 27、空白键是 32
。 其他的像↑、↓、→、←、PgUp、PgDn、F1 等的内码又是
如何呢?这些键用程式 5-1 所侦测到的内码都是 0, 但是萤
光幕上却显示出一些字元。内码值与萤光幕所显示字元的内码
值不一样,主要是因为这几个键是属於扩充键,当程式扫描到
扩充键时,会传回两个码,扩充码的第一个码是 0,第二个码
才是这个键的码, 所以用程式 5-1 是扫描不到这些扩充码的
。
【程式 5-2 】
1'5-2
2 CLS
3 DO
4 LOCATE 1, 1
5 PRINT TIME$
6 A$ = INKEY$
7 LOOP UNTIL A$ <> ""
8 IF LEN(A$)=2 THEN A$ = RIGHT$(A$,1)
9 KEYCODE = ASC(A$,1)
10 PRINT KEYCODE
11 END
说明:程式加了第八行, 判断是否按了扩充键,若是扩充键则取
其第二个字元。
(4) 重要按键的内码值
Enter:13 F1 :扩充码 59
Spc :32 F2 :扩充码 60
Esc :27 .
↑ :扩充码 72 .
↓ :扩充码 80 F10 :扩充码 68
→ :扩充码 77 Ins :扩充码 82
← :扩充码 75 Del :扩充码 83
PgUp :扩充码 73 Home:扩充码 71
PgDn :扩充码 81 End :扩充码 79
一些组合键也可以扫描到。如下:
Ctrl-Enter:扩充码 10
Ctrl-Spc :扩充码 32
Ctrl-F1 :扩充码 94
其馀的内码可以参考内码表。
(5) 如何克服扩充码与正常码冲突的问题?
为了程式上的方便,通常把扩充码的值加上负号,这样在程式
上就非常好辨认。
【程式5-3】
1 '5-3
2 CLS
3 DO
4 LOCATE 1, 1
5 PRINT TIME$
6 A$ = INKEY$
7 LOOP UNTIL A$ <> ""
8 IF LEN(A$)=2 THEN
9 KEYCODE= -ASC( RIGHT$(A$,1))
10 ELSE
11 KEYCODE = ASC(A$,1)
12 END IF
13 PRINT KEYCODE
14 END
说明:程式#8 ~#11 判断是否按了扩充键,若是扩充键则取其第
二个字元,并将扫描码加上负号。
3.计时器
计时在 CAI 中是经常用到的。 如待答时间、观看教学画面、特别
是在游戏式的 CAI 中用的更多。
【程式5-4】
1 '5-4
2 DEFTIME = 10
3 START = TIMER
4 DO
5 IF TIMER - STARTIME > 1 THEN
6 DEFTIME = DEFTIME -1
7 STARTIME = TIMER
8 LOCATE 10 ,40 : PRINT DEFTIME
9 END IF
10 LOOP UNTILL DEFTIME = 0
11 PRINT "TIMER IS VVER !"
12 END
说明:倒数计时十秒钟,每隔一秒钟显示所剩秒数。这个程式在到
数计时过程中,程式只有计时功能,并没有扫描使用者的按
键。
【程式5-5】
1 '5-5
2 DEFTIME=10
3 STARTIME = TIMER
4 DO
5 IN$ = INKEY$
6 IF TIMER - STARTIME > 1 THEN
7 DEFTIME = DEFTIME -1
8 STARTIME = TIMER
9 PRINT DEFTIME
10 END IF
11 LOOP UNTIL IN$ <> "" OR IN$ <> ""
12 IF DEFTIME = 0 THEN
13 PRINT "TIME IS OVER !"
14 ELSE
15 IF LEN(IN$) = 2 THEN
16 KEYCODE = ASC(MID$(IN$,2,1))
17 ELSE
18 KEYCODE = ASC(IN$)
19 END IF
20 PRINT "KEYCODE IS "; KEYCODE
21 END IF
说明:(1) 这个程式可以倒数计时, 同时也侦测使用者的按键,
使用者按任意键, 程式结束,并显示所剩馀时间及按
键内码值。
(2) #4 行到 #11 行,为一回路, 终止条件是按任一键或
计时终了。 在这回路中,一直在做两件事,键盘扫描
、倒数计时。
(3) #12 行到 #21 行,判断按键或计时终了,若计时终了
(#16) 则显示 " TIME IS OVER! "; #14 到 #20,处
理按键的内码值, #13 扩充键的处理,#18 一般按键
内码值处理。 #21 显示出按键内码值。
5-2 音乐开关
很多软体,按 S 键可以控制声音的有无,S 键就如声音的开关。 我
们先看几个简单的程式。
【程式5-6】
1 '5-6
2 DO
3 IN$ = INKEY$
4 S% = RND * 5000 + 200
5 SOUND S%, 0.5
6 LOOP UNTIL IN$ <> ""
说明:随机发出一频率从 200 至 5200 音长为 0.5 的音来。按任一
键程式结束。在回路中程式做叁件事,扫描键盘、取乱数、发
音。
【程式5-7】
1 '5-7
2 ONOFF$ = "ON"
3 DO
4 DO
5 IN$ = UCASE$(INKEY$)
6 IF ONOFF$ = "ON" THEN
7 S% = RND * 5000 + 200
8 SOUND S%, 0.5
9 END IF
10 LOOP UNTIL IN$ = "S"
11 SELECT CASE ONOFF$
12 CASE "ON"
13 ONOFF$ = "OFF"
14 CASE "OFF"
15 ONOFF$ = "ON"
16 END SELECT
17 LOOP UNTIL IN$ = CHR$(27)
说明:(1) 程式 5-7 按 S 键,可以控制声音的有无。
(2) 变数说明 ONOFF$ 开关,初值为"ON",表示"开"。
"OFF" 表示关。
(3) #3 行:UCASE$ 函数会将输入的字元转换成大写, 如此,
就不需要在程式中再检查大小写。 英文字母大小写分别是
不同的内码。如大写 A 内码是 65,小写 a 是 97。
IN$ = UCASE$(INKEY$)
IN$ 所扫描到的英文字母都是大写的。
(4) #11 ~ #16,双向开关设定。 所谓双向开关就如公寓之楼
梯灯开关,若灯开着,按下开关,灯就会息掉; 若灯未开
,按此开关,灯就会开。同理,若有音乐,按下 S 键,音
乐就关掉;若无音乐,按下 S 键,音乐就开了。
用程式语言表示:
IF ONOFF$ = "ON" THEN ONOFF$ = "OFF" ELSE
ONOFF$="ON"
程式 5-7 的 #11 ~ #16 行也是一样。
SELECT CASE
ONOFF$
CASE "ON"
ONOFF$ = "OFF"
CASE "OFF"
ONOFF$ = "ON"
END SELECT
ONOFF$ 变数需配合 #6 ~ #9 行,来控制声音有无。也可
以用程式 5-8 的方法来控制声音的开与关。
【程式5-8】
1 '5-8
2 ONOFF% = 1
3 DO
4 DO
5 IN$ = UCASE$(INKEY$)
6 S% = RND * 5000 + 200
7 SOUND S%, 0.5 * ONOFF%
8 LOOP UNTIL IN$ = "S"
9 SELECT CASE ONOFF%
10 CASE 1
11 ONOFF% = 0
12 CASE 0
13 ONOFF% = 1
14 END SELECT
15 LOOP UNTIL IN$ = CHR$(27)
说明:(1) 这个程式与 5-7 架构雷同, 不同处是程式 5-8 用变数
ONOFF 为数字变数,这个 ONOFF 变数不但是开关也控制着
音长。 当 ONOFF% = 1 则 SOUND S%, 0.5 * ONOFF% 音长
是 0.5 * ONOFF% 等於 0.5。 当变数 ONOFF% = 0 时音长
是 0.5 * ONOFF% 等於 0,所以不发声,没有音乐。
(2) 这种方法与 SOUND 指令配合, 效果相当好。 但是若用
PLAY 指令则用程式 5-7 的方法比较好。
【程式5-9】
'5-9
SOU% = 1
DO
IN$ = UCASE$(INKEY$)
LOCATE 1, 1 : PRINT TIME$
SELECT CASE IN$
CASE "S"
SELECT CASE SOU%
CASE 1
PRINT "SOUND IS OFF !"
SOU%=0
CASE 0
PRINT "SOUND IS ON !"
SOU%=1
END SELECT
END SELECT
PIC% = RND * 5000 + 200
SOUND PIC%, 0.5 * SOU%
LOOP UNTIL I$ = CHR$(27)
END
说明:(1) 这个程式与 5-8 执行的结果完全一样。但是程式的架构却
不一样,这个程式把声音的开关放在回路里面。
(2) 如果要加上倒数计时,并同时发声要如何设计呢?
5-3 背景音乐
所谓背景音乐的意思就是,有画面、有声音。当然这个画面不是静态
的。
【程式5-10】
'5-10
SOU% = 1
DO
IN$ = UCASE$(INKEY$)
LOCATE 1, 1 : PRINT TIME$
SELECT CASE IN$
CASE "S"
SELECT CASE SOU%
CASE 1
PRINT "SOUND IS OFF !"
SOU%=0
CASE 0
PRINT "SOUND IS ON !"
SOU%=1
END SELECT
END SELECT
PIT% = RND * 5000 + 200
SOUND PIT%, 0.5 * SOU%
X% = RND * 639
Y% = RND * 348
CLOR% = RND * 15
PSET (X%, Y%), COLR%
LOOP UNTIL I$ = CHR$(27)
END
说明:(1) 这个程式执行後萤光幕会有满天星、 并有声音出现、同时
显示时间、并扫描键盘。如果按 S 键,声音关掉,并显示
"SOUND OFF!",
(2) 前面几个例子,都是关於音效方面的,用 SOUND 指令来编
一首歌曲,可以用 READ DATA 的方法,比较起来仍然是没
有效率的。
【程式5-11】
1 '5-11
2 CLS
3 PLAY "MB"
4 DO
5 LOCATE 1, 1
6 PRINT "NUMBER OF NOTES LEFT TO PLAY:";
7 IF PLAY(1) < 3 THEN
8 PLAY "O3CDEFGAB>C"
9 END IF
10 PRINT PLAY(1)
11 LOOP UNTIL INKEY$ <> ""
说明:(1) 这个程式利用 PLAY 函数知道缓冲区中还剩下多少音符。
(2) #7 行表示如果缓冲区中的音符小於 3,则重新执行 #8 行
PLAY。如此缓冲区一直都有音符,音乐就不会终止。
(3) #10 行是把缓冲区中还剩下的音符数印出来。
【程式5-12】
1 '5-12
2 SCREEN 9 :CLS
3 DIM SOU$(7)
4 SOU$(1) = "O3L8GL16ECE"
5 SOU$(2) = "L8DL16GFC "
6 SOU$(3) = "O3CEG>C"
7 SOU$(4) = "C 7 THEN I% = 1
20 PLAY "X" + VARPTR$(SOU$(I%))
21 END IF
22 LOOP UNTIL INKEY$ <> ""
说明:(1) 执行这个程式萤光幕会呈现放射状的直线,还有反覆不断
的音乐。按任一键程式结束。
(2) #2 设定绘图页,用模式 9。
(3) #3 定义一个 SOU$音乐阵列。
(4) #4~#10 设定音乐阵列中的音乐资料。
(5) #12~#22 是一个回路,按任一键程式终止。
(6) #13 取一整数乱数X%, 围 0~639 。
#14 取一整数乱数Y%, 围 0~348 。
#15 取一整数乱数COLR%, 围 0~15。
#16 依所取之 X%、Y%、COLR% 之值,用 COLR% 颜色,从
座标 (320, 174), 萤光幕中心位置画一条线到座标
(X%,Y%)。
(7) #17 ~ #21 判断缓冲区中的音符资料是否小於 3, 如果
小馀 3,则执行 #18 ~ #20 行,设定缓冲区中的音符资
料,#18 #19 行是做音乐阵列的检查, 当 I>7 时,表示
乐曲结束,重新设定 I=1, 音乐又重新开始。 如此反覆
#13 ~ #22,直到按任一键,程式才终止。
【程式5-13】
1 '5-13
2 SCREEN 9: CLS
3 SOU$(1) = "O3L8GL16ECE"
4 SOU$(2) = "L8DL16GFC "
5 SOU$(3) = "O3CEG>C"
6 SOU$(4) = "C 7 THEN I = 1
40 PLAY "X" + VARPTR$(SOU$(I))
41 RETURN
说明:(1) 这个程式执行的结果与程式 5-12 相同,但是多了一个音
乐的开关。
(2) #19 ON PLAY(3) GOSUB replay, 当缓冲区中的音符资料
小於 3 时则 GOSUB replay,replay 是一个副程式, 控
制缓冲区中的音符资料内容,让音乐不断反覆。
(3) #24 ~ #34 又是一种控制音乐开关的方法, 这种方法需
配合 PLAY ON 来使用。
6-4 BSAVE 指令介绍
BSAVE 指令主要是将阵列中的资料,存到磁片中的档案。如果阵列中
的资料是图形资料,就如同将图形存起来一样。
【程式6-6】
1 '6-6
2 SCREEN 3,, 1, 1
3 DIM PIC%(38)
4 LINE (12,0)-(0,12)
5 LINE (12,0)-(23,12)
6 LINE (5,9)-(19,23),1,B
7 LINE (5,9)-(19,9),0
8 GET (0,0)-(23,23),PIC%
9 DEF SEG = VARSEG(PIC%(0))
10 BSAVE "PIC1.BLD", VARPTR(PIC%(0)),76
11 DEF SEG
12 END
说明:(1) 这个程式是将阵列 PIC% 以档名 "PIC1 .BLD" 存入。而
阵列 PIC% 内资料为 #4 行至 #7 行所画的房子。
(2) #8 行,捉取图形资料。
(3) #9 行,DEF SEG = VARSEG(PIC%(0)) 定义记忆体区段起
始位置。区段起始位置是阵列 PIC% 第 0 个阵列的位置
。 VARSEG 函式是传回变数所在的区段位址。
(4) #10 行, BSAVE "PIC1.BLD", VARPTR(PIC%(0)), 76
VARPTR 函式是传回变数所指区段位址的节内位址。这个
函式在 PLAY 中经常用到。从 PIC%(0) 的位置开始存76
个 BYTE 长度的资料到档案 PIC1.BLD 中。
(5) QB 对记忆体的应用,分成两个区域:内定资料区段:受
64K 限制。远程推积区段:不受 64K 限制。可用动态阵
列、 或经过 REM $DYNAMIC 宣告的静态阵列都可使用到
本区。
6-5 BLOAD 指令介绍
BSAVE 指令须有 BLOAD 指令来配合, 这两个指令,是直接对记忆体
做存取的动作,其速度是相当的快,是非常有效率的两个指令。
【程式6-7】
1 '6-7
2 SCREEN 3,, 1, 1
3 DIM PIC%(38)
9 DEF SEG = VARSEG(PIC%(0))
10 BLOAD "PIC.BLD", VARPTR(PIC%(0))
11 DEF SEG
12 FOR X = 1 TO 680 STEP 50
13 FOR Y=1 TO 300 STEP 50
14 PUT (X,Y),PIC%,PSET
15 NEXT
16 NEXT
17 END
说明:(1) 这个程式是将程式 6-6 所存的图形资料, 载入记忆体中
,并将图形显示出来。
(2) #3 行,定义图形阵列大小。
(3) #4 行,定义区段位址是从阵列第0个开始。
(4) #10 将图形资料档,直接载入到所指定的记忆体位址中。
即阵列第 0 个位置。
(5) #12至#16 将图形显示出来。
(6) 对於图形阵列大小如何得知?在 #3 行,定义阵列大小,
是因为在程式 6-6 中已经得知。 如果档案很多时,要如
何得知呢?请看程式 6-8 。
【程式6-8】
1 '6-8
2 SCREEN 3,, 0, 1
3 OPEN "I", #1, "PIC.BLD"
4 NUMBYTE= LOF(1)
5 CLOSE #1
6 DIM PIC%(NUMBYTE/2)
7 DEF SEG = VARSEG(PIC%(0))
8 BLOAD "PIC.BLD", VARPTR(PIC%(0))
9 DEF SEG
10 FOR X = 1 TO 680 STEP 50
11 FOR Y=1 TO 300 STEP 50
12 PUT (X,Y),PIC%,PSET
13 NEXT
14 NEXT
15 SLEEP
16 SCREEN 3,,0,0
17 END
说明:(1) 这个程式和程式6-7 执行的结果一样。
(2) #2 设定画图页是第0页,显示页是第一页。
(3) #3至#5,侦测档案大小。LOF(1)传回该档案的大小。
(4) 利用侦测到的档案大小,定义阵列大小。 由於所使用的
为整数阵列, 整数阵列每一个阵列为 2 个 BYTE,因此
,只需要一半的阵列数即可。
(5) #10至#14,在绘图页(背景页)显示图像。
(6) 切换显示页为第0页。