操作性の向上あるいはMMIの改善(続・連立二元一次方程式への挑戦)

 前回の私のブログ記事の最後に、「今回作ったプログラムの操作性をもっとよくできるはずだ。」みたいなことを書きました。画面上のウィンドウ内で、連立二元一次方程式を表す二行の文字列
?x+?y=?
?x+?y=?
の”?”の部分に数値を入れて、『xとyを求める』ボタンを押すという操作手順を、このプログラムを利用する時に、私たち人間は何度も繰り返すことでしょう。そう考えてみると、その操作手順がなるべく簡単で、ムダなキーボード操作が少ないと、使いやすいことがわかります。私たち人間が、コンピュータプログラムと数値などの情報(データ)をやり取りするための仕組み、すなわち、マン・マシン・インターフェース(Man-Machine Interface: 今回も、以下MMIと略します。)を工夫して、それを改善することが重要だということがわかります。
 ところで、ウィンドウズでは、HTMLやVBスクリプト・Jスクリプトなどの簡易言語が標準装備されています。人によっては、そんな簡易言語など、CやJavaなどのちゃんとした言語処理システムと比較したならば、全然使い物にならないという意見の方もいらっしゃると思います。私は、その意見を否定するつもりはありません。ただ、私は、どんなコンピュータでも、それを利用するのに小さなプログラムで簡単に操作できる、そんなシステムがあると便利だと思っているだけなのです。私は、しばしば過去において、コンピュータのプログラミングが難しくて、「コンピュータ嫌い」や「コンピュータ離れ」になってしまいそうになりました。そんな窮地を救ってくれて、プログラミングを続けさせてくれたのが、ウィンドウズに標準搭載されていたそうした簡易言語だったのです。
 私も、その使いたての最初のうちは、マニュアルに書いてある通りのプログラミングをしていました。簡易言語に普通に用意されていた命令やタグやオブジェクトなどを、決まりきった普通の使い方でプログラムを組むのに使っていました。そのうちに、私自身満足がいくものを作ってみようと考えた時に、どうしても既存の材料やその標準的な使い方では作れない、という困難に突き当たりました。そこで、マニュアルを事細かく調べたり、テストプログラムを作って実際に動かしてみたりして、あれこれできないかと考えるようになりました。
 今回のプログラムにしても、”?”に数値を入れている部分を、HTMLのINPUTタグなどを使って、画面上のウィンドウ内に6個所の空欄枠付きの入力フィールドを作れば簡単です。それが、ごく普通の、いわゆる「標準的な」プログラミングです。けれども、私は、他の人がC言語で作った、画面上に多数の空欄枠付きの入力フィールドを並べたプログラムを見たことがありました。インターネットのサイトのベクターからダウンロードをしたフリーウェアのプログラムでした。それをキーボードで操作してみて、何か使いずらいなと私は思いました。別に、そのプログラムを作った人が悪いのではありませんが、標準的な入力枠付きフィールドが多数並んでいる、その画面レイアウトが何となく私には気に入りませんでした。(という私も、仕事でプログラマをやっていた20代の頃は、クライアント(顧客)や上司先輩の指示命令で、それと同じような画面レイアウトのプログラムを作っていました。)
 そこで、「標準的な」入力枠付きフィールドをいっさい使わずに、数値を入れたい”?”の画面上の位置に矢印カーソルを移動させるだけ、という今回のスタイルにしてみたわけです。そのように、数値の取り込ませ方をなるべく簡略化することによって、従来のコンピュータの使いづらさや面倒くささを少しでも改善したかったわけです。
 そのことは、”?”の箇所全部に数値を入れてから『xとyを求める』ボタンを押して、方程式の計算を開始させるという、操作の手順にも言えることでした。いっそのこと、そのボタンをなくしてしまおう、と私は次に考えました。キーボードからの打ち込みにより、”?”の箇所全部に数値が入ったそのタイミングで方程式の計算を開始すれば、マウスで毎回そのボタンを押す手間が省けます。些細なことに思われるかもしれませんが、毎回計算を始めるためにボタンを押さなくても、自動的に計算を始めてその結果を出してくれるのは、キーボードを打つ人間の利用者(ユーザ)側から考えてもお得な話です。まさに昔、電卓のCMのキャッチフレーズに使われた「答え一発。」という言葉そのままに、その便利さを実現できる仕組みと言えましょう。
 実際にコンピュータでそのプログラムを動かしてみると、画面上のウィンドウ内から”?”が全部なくなったその瞬間、あるいは数値の変更があったその瞬間に、xとyの値が求まって、その計算結果が画面に出てきました。”?”が画面上から消えてなくなった後は、キーボードからのワンキー(one key)ごとの操作で新たな数値が定まって、刻々とその計算結果も変化してゆきました。これこそが、今回私が目指した操作性の向上あるいはMMIの改善でした。それでは、今回そのように作り変えたプログラムの内容を以下に示しましょう。


連立二元一次方程式v1.50.hta

<STYLE TYPE="text/css">

  BODY  { background-color:rgb(80%,70%,70%); overflow:auto; }
  SPAN  { font-size:20pt; height:20pt; padding:4pt; margin:3pt 0pt;
          cursor:default; }
  .coef { font-size:24pt; }
  .fita { font-size:20pt; font-style:italic; }

</STYLE>

<HTA:Application Id=oHTA Scroll=no  Contextmenu=no />


<BODY scroll=No>

<SPAN CLASS=coef id=c1 >?</SPAN><SPAN CLASS=fita >x</SPAN>
<SPAN> + </SPAN>
<SPAN CLASS=coef id=c2 >?</SPAN><SPAN CLASS=fita >y</SPAN>
<SPAN> = </SPAN>
<SPAN CLASS=coef id=c0 >?</SPAN><BR>

<SPAN CLASS=coef id=c1 >?</SPAN><SPAN CLASS=fita >x</SPAN>
<SPAN> + </SPAN>
<SPAN CLASS=coef id=c2 >?</SPAN><SPAN CLASS=fita >y</SPAN>
<SPAN> = </SPAN>
<SPAN CLASS=coef id=c0 >?</SPAN><P>

<SPAN id=Mes ></SPAN>


</BODY>


<SCRIPT language="VBScript">
Option Explicit

Dim target


Call ResizeTo(400, 280)

Document.Title = "連立二元一次方程式"


Sub Document_Onmouseover

    Set target = Window.event.srcElement

    If target.classname = "coef" Then

       If target.style.color = "" Then

          target.style.color = "red"

       End If

    End If

End Sub


Sub Document_Onmouseout

    Set target = Window.event.srcElement

    If target.classname = "coef" Then

       If target.style.color = "red" Then

          target.style.color = ""

       End If

    End If

End Sub


Sub Document_OnkeyPress
    Dim tk, kc


    tk = Window.event.keyCode
    kc = Chr(tk)

    If kc = "?" Then

       Mes.InnerText = KeyinQMark() 
       Exit Sub

    End If


    If target.classname <> "coef" Then Exit Sub

    If tk = 8 Then   ' Backspace code?

       Mes.InnerText = KeyinBackspace()

    ElseIf kc = "-" Then

       Mes.InnerText = KeyinMinus()

    Else

        Mes.InnerText = KeyinNumber(kc)

    End If

End Sub


Private Function KeyinQMark()

    c1(0).InnerText = "?"
    c1(1).InnerText = "?"
    c2(0).InnerText = "?"
    c2(1).InnerText = "?"
    c0(0).InnerText = "?"
    c0(1).InnerText = "?"

    KeyinQMark = ""

End Function


Private Function KeyinBackspace()
    Dim wv

    If target.InnerText = "?" Then

       KeyinBackspace = "まず数値を入れてください。"

    Else

       wv = Abs(Eval(target.InnerText))

       If wv < 10 Then

          target.InnerText = "?"

       Else       

          target.InnerText = Cstr(wv \ 10)

       End If

       KeyinBackspace = TryAnswer()

    End If

End Function


Private Function KeyinMinus()
    Dim wv

    If target.InnerText = "?" Then

       KeyinMinus = "まず数値を入れてください。"

    Else

       wv = 0 - Eval(target.InnerText)

       If wv < 0 Then

          target.InnerText = "(" & wv & ")"

       Else

          target.InnerText = wv

       End If

       KeyinMinus = TryAnswer()

    End If

End Function


Private Function KeyinNumber(kc)
    Dim idx, wv


    idx = InStr(1, "0123456789", kc)

    If idx > 0 Then

       If target.InnerText = "?" Then

          wv = 0

       Else

          wv = Eval(target.InnerText) * 10

       End If

       target.InnerText = Cstr(wv + idx - 1)

       KeyinNumber = TryAnswer()

    Else

       KeyinNumber = "数値しか入りません。"

    End If

End Function


Private Function TryAnswer()

   If QMarkCheck() Then

      TryAnswer = ""

   Else

      TryAnswer = calcMatrix()

    End If

End Function


Private Function QMarkcheck()

    If c1(0).InnerText = "?" Or c1(1).InnerText = "?" Or _
       c2(0).InnerText = "?" Or c2(1).InnerText = "?" Or _
       c0(0).InnerText = "?" Or c0(1).InnerText = "?" Then

       QMarkcheck = True

    Else

       QMarkcheck = False

    End If

End Function


Private Function calcMatrix()
    Dim rstr, delta, elm_x, elm_y, d1(1), d2(1), d0(1)

    d1(0) = Eval(c1(0).InnerText)
    d1(1) = Eval(c1(1).InnerText)
    d2(0) = Eval(c2(0).InnerText)
    d2(1) = Eval(c2(1).InnerText)
    d0(0) = Eval(c0(0).InnerText)
    d0(1) = Eval(c0(1).InnerText)

    delta = d1(0) * d2(1) - d2(0) * d1(1)
    elm_x = d2(1) * d0(0) - d2(0) * d0(1)
    elm_y = d1(0) * d0(1) - d1(1) * d0(0)

    If delta = 0 Then

       rstr = "連立方程式ではありません。"

    Else

       rstr = "x  = " & Reduce(elm_x, delta) & " , " &_
              "y  = " & Reduce(elm_y, delta)

    End If

    calcMatrix = rstr

End Function


Private Function Reduce(child, adult)
    Dim rstr, idx, clower, alower, prefix, surfix
    Dim chsg, adsg, chpv, adpv, rsig


    If child < 0 Then

       chsg = -1
       chpv = Abs(child)

    Else

       chsg = 1
       chpv = child

    End If


    If adult < 0 Then

       adsg = -1
       adpv = Abs(adult)

    Else

       adsg = 1
       adpv = adult

    End If


    If chpv = adpv Then

       Reduce = Cstr(child \ adult)

       Exit Function

    End If


    For idx = adpv to 2 step -1

        If adpv mod idx = 0 Then

           If chpv mod idx = 0 Then

              Exit For

           End If

        End If

    Next

    clower = chpv \ idx
    alower = adpv \ idx
    rsig = chsg * adsg

    If alower = 1 Then

       rstr = Cstr(clower \ alower * rsig)

    Else

        If rsig = -1 Then

           prefix = "-("
           surfix = ")"

        Else

           prefix = ""
           surfix = ""

        End If

        rstr = prefix & clower & " / " & alower & surfix

    End If

    Reduce = rstr

End Function


</SCRIPT>


 前バージョン(連立二元一次方程式v1.00.hta)のプログラム内容と今回のバージョンを比較しますと、方程式の計算のプログラム部分は、全く変わっていません。つまり、プログラムで修正した部分は、ボタンの画面レイアウトとその処理に関わる部分だけです。『xとyを求める』ボタンが押された時に行われていた処理は、キーボードの打ちこみ毎の処理に変更しました。つまり、キーボードからの打ちこみで必要な数値が全てそろった直後に、その計算処理を開始します。そのような処理を、一つの関数(TryAnswerという関数)にまとめて、プログラム中の必要な箇所に配置しました。
 また、画面レイアウト上からは、『xとyを求める』ボタンと共に『数値のクリア』ボタンもなくしました。数値を全てクリアする場合は、”?”キーを押します。すると、画面上のウィンドウ内は、初期状態の”?”だらけの連立方程式に戻ります。この”?”キーは、いわゆる隠れキーです。『数値のクリア』ボタンはなくなりましたが、それまでの処理は”?”キーを押した場合の処理に移しました。
 もともと、それらのボタンはHTMLの標準で用意されているINPUTタグで作ったボタンでは実はありませんでした。私が、SPANタグにスタイルシートとVBスクリプトで細工をして作った『疑似ボタン(あるいは、言葉は悪いですが、フェイクなボタン)』でした。せっかく自作したのですが、今回のプログラムの操作性向上、すなわち、MMIの改善のために、お払い箱となりました。
 これで、今回のプログラムのバージョンアップは終わりとなります。ただし、欲を言えば、さらなるバージョンアップが考えられます。それはどういうものかと申しますと、小数値が打ちこめるようにプログラムを修正することです。そんなの大したことないじゃないか、と思われるかもしれません。今のプログラムでは、整数の数値が扱えるように作ってあります。それを整数値から小数値にすればよいのですが、計算結果を分数で画面に出す時に、その分母や分子が小数になって、わかりにくい複雑な数値となってしまう場合があるようです。
 それを解決する方法の一つは、次のとおりです。キーボードから打ちこまれた数値が小数であるならば、いったん分数に変換して、計算処理も分数で行うのです。もしも時間の余裕があったならば、この数式の実生活への応用範囲を広げるという意味でも、いつかそれにトライしてみたいと思っています。