回 帖 发 新 帖 刷新版面

主题: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页。


回复列表 (共1个回复)

沙发

哪里弄来的[em10]

我来回复

您尚未登录,请登录后再回复。点此登录或注册