I also want to enter the triangle mark!

「(採点ソフトで)〇と × だけじゃなく△も入力したい!」

手書き答案を採点するプログラムを書いた。当初の予定では、採点記号は正解(〇)か、不正解(×)のみとして、正解(〇)の場合は、その得点を採点記号の右に表示できるように設定したから、その点数の大小によってそれが完全正解なのか、△(部分点あり)なのかを判別できればイイ、「だから△なんてイラナイ」と、僕は考えていたんだけれど・・・。

今にして思えば、弱い自分への言い訳でした・・・ T_T

ほぼ完成に近づいたMy手書き答案採点プログラムのイメージ。
(この時点で、本人は「完成した」と思っていた・・・)

No,2とNo,6の -5x は完全正解の半分の2点しかあげないけど、でも × じゃないよー。みたいな・・・

でも、そんな時、偶然、Webのニュースで見ちゃったんだけど、東京都が公的に導入した業務改善用の採点ソフトでは・・・

あたりまえのコトですが、
採点記号に△も使ってるんですよ!

僕のプログラムでは、絶対に「表示できない」△マーク。
別に△マークがあったって、エラくなんか、ないもん・・・。うぐぐ。

でも、それって、
走召!ぐやじい!!!
じゃありませんか。

僕のプログラムの完成なんて、誰ひとり、待ってないケド・・・

一般庶民のフツーの感覚で言えば(僕の感覚と常識が正しいとして)、一昨年、
一般庶民には買えない価格のDelphiを、「個人で購入するという暴挙に出た」僕です

それはDelphiが、Object Pascalが好きだから。
出会った時から、ずっと 大好きな・・・Delphiの・・・
この文化が消えないように、この言語がいつまでも残るように、
Delphiと、Object Pascalが、ほんとうに大好きだからやったことなんだけど・・・。

あれだけの初期使用料と、高額な年度ごとのサブスクリプション代金を支払っても・・・。
僕はイイから。

(結婚した時、印鑑といっしょに、彼女に取り上げられた通帳の、今はまったく自由にならない預金口座からの引き落としだから、実は痛くもかゆくもないんだケド・・・ *(^_^)*♪ )


こんなに・・・。
どうしようもない、くらい、こんなに・・・。

こんなに Delphiが好きなのに、
たかが△マークすら表示できない・・・
なんて・・・


許せないよ・・・
絶対に許せない・・・


アマチュアとか、プロとか、関係なく、
△マークの表示が、東京都の御用達プログラムに出来て、
僕に出来ない理由なんて、
それをあきらめる場合以外には、探したくないし、
あきらめなければ、僕にもきっと出来るはずです。

アマチュアとか、プロであるとか、は関係ない。
△マークの有無が問題なのだ。

それが「ない」プログラムは、
決して、良い採点プログラムとは言えない!

なんでこんな大事なコトに今まで気づかなかったんだ・・・
(アンタにとって、それはいつものことでしょ)

よぉぉぉぉぉぉぉぉぉぉっし、
俺はやるぞ!!!

そう思ったら、思い出せました。

よくなりたい、自分を。

(長すぎる前置きですが、どうしても、話したかったことはここから・・・)

【もくじ】

1.△の使用をあきらめた理由
2.マイナスの点数は通常ありえないコトに気づく
3.採点アルゴリズムを改良
4.合計点の計算と印刷
5.まとめ
6.お願いとお断り

1.△の使用をあきらめた理由

手書き答案をスキャナーで読み取り、各設問毎に画像を切り出して合成、素早く・効率よく採点、で、採点記号&得点付き画像を元の答案画像へ書き戻し、合計点を付加(任意の位置に表示)して返却用答案を印刷するプログラムを作成した。

下の画像はその実行時のイメージ。Gridコントロールへ入力した数値に応じて答案画像の上に採点記号(〇 もしくは × )と、〇の場合は得点を表示している。× の場合に得点の表示がないのは、0と〇がよく似ていて、×0という表記は間違いなく混乱を招くと考えたため。いちおう、オプション設定で表示の有無を選択できるようにはしてあるが、デフォルト設定で「得点0は表示しない」のチェックはON。

×0は混乱のもと!(表示する選択肢は提供)
No,2とNo,6には 本当は△を表示 したい・・・

当初は次のような理由から採点記号△の使用を断念してしまった・・・。

ほんとうは 〇・× の他に採点記号として△も使いたかったのだ。が、採点の基本としたアルゴリズムではGridコントロールに「正の数が入力」された場合は正解で採点記号は「 〇 」、「0(ゼロ)が入力」されていたら不正解で採点記号は「 × 」、「空欄」の場合は何もしないと決めていたので、△の入り込む隙が見出せなかった・・・というのが一つ。

また、これは直接△とは関係ないけれど、人間である以上、採点ミスはつきもの!で、答案画像に採点記号と部分点を埋め込むのは最後の最後。返却用答案画像を作成する直前でなければならない。それまでは、Gridコントロールへの得点入力に応じて、採点記号を付加した答案画像をいつでも修正可能な状態にしておく必要がある。

もし、強引に「部分点あり」の採点記号を「△」にするなら、Gridコントロールへの入力値から、この「△」を見分ける手段を考えなければならない。この手段を思いつかなかったというのが一つ(当初から考えなかったわけではないが・・・、スマートな方法をどうしても見いだせなかった)。

さらに得点入力のしやすさを考えると、テンキーがあってもなくても、0(ゼロ)はキーボードの右側にあって、どうにも押しにくい(マウスを操作する右手は、マウスから離したくない & 左手で何回も0を押すのは、かなりめんどくさい)から、数値以外の入力はすべて0(ゼロ)と見なすプログラムを書けば、A・S・Dあたりのキーを押すことで理想的(?)に0(ゼロ)を入力できる。また、答案画像のクリック位置とGridコントロールのフォーカス位置が連動するようにプログラミングすれば、ぱっと見、全体的に出来の良い設問への得点入力は、プログラムから一括で行い、あとは間違いの解答だけ、その画像をクリックしてAキーあたりを押して0(ゼロ)を入力すれば、いちばん効率よく採点できる・・・はず。逆に、ぱっと見、全体的に出来が悪そうなら、一括して0(ゼロ)を入力し、正解の解答だけ選択して得点を入力すればいい。多くの場合、正解の得点は5点未満だろうから、これらのキーはキーボードの左にあり、左手で押しやすい。

百歩ゆずって、あるキー(例:「さんかく」だから「s」キーとか)を押した場合だけ、採点記号を△とするのは容易だが、後々やっかいな問題が生じる。

プログラムは最終的に、Gridコントロール上のデータから、合計点を計算して返却用答案画像のどこかに印刷する仕様。で、その際、データに余計な文字があれば除外して計算することも出来なくはないが、予期せぬ間違いの元になるような要素は、なるべくなら最初から排除しておきたい。かといって、△マークであることを示すなんらかのフラグをデータとして持っていなければ、データを再読み込みした際に、画像上に△記号を表示することはできない・・・。しかし、そのために、Gridコントロール上に「採点記号・部分点」を意味する「s1」みたいな表示をするのは、できるだけ避けたい。Gridコントロール上に数値以外の文字が「ない」のが、最初からの理想なのだ。

実は、見えないGridコントロールをもう一つ、別に準備してここに「〇・△・×」の情報を記録しようか・・・とも考え、実際にやってみたんだけど、これだとアルゴリズム他をかなり修正しないといけないことに気づく。なので、この案は却下。

で、八方塞がり状態に・・・

2.マイナスの点数は通常ありえないコトに気づく

(やっぱり、ダメかぁー)

そう思いながら、それでもあきらめきれずに、なんとなくStringGrid1DrawCell手続きのコードを眺めていて、次のコードを残したままだったことに気づく。

  //正負をチェック
  if StrToInt(StringGrid1.Cells[ACol,ARow])< 0 then
  begin
    StringGrid1.Canvas.Font.Color := clRed;
  end else begin
    StringGrid1.Canvas.Font.Color := clBlack;
  end;

これは、いつか他のプログラムで使用したコードを、このプログラムにコピーした際、そのままになっていたものだ。別に問題を起こすようにも見えなかったし、通常の採点でマイナス点の入力はアリエナイから、誤って? 負の数が入力されたら赤く表示した方が入力ミス?が防げてかえってイイか・・・くらいの気持ちで、消さずに残しておいたのだ。

何度も実行して検証したプログラムコードだけれど、このプログラムでは「負の数の入力」は最初から予定に「ない」ので、負の数は一度も入力したことがなかった・・・し、このコードを消さずに残しておいたこと自体を、その存在に気づくまで、僕は忘れていた。

(こんなコードも入ってたんだ・・・)

その瞬間、何かが、ひらめいた気がした・・・

(そうか! 負の数をフラグに使う手があった☆)

本質的に文字だと計算上、いろいろ問題が起きるけど、負の数なら絶対値をとってしまえば合計点の計算は何の問題もなくできるし、さらに良いことに、これまで何よりも問題だった△を意味するフラグとして、-の記号を利用できる!!

赤で表示する設定になってることも、ユーザーにとって親切だし・・・。僕的に言えば、「△なら部分点に-(マイナス)記号をつけて入力」なんだけど、これを一般的に言えば「部分点を与える場合は、負の数として入力してください」ってことで、これならユーザーに確実に伝わるし、かつ覚えやすい。

さらに採点アルゴリズムも全体の大幅な見直しは不要で、Gridコントロールのデータが負の数であった場合の処理だけを追加すればよさそうだ。

なんで、こんなイイことに最初から気づかなかったのか、それは僕が足りないせいだけど、そんなことはどーでもイイ。なんだがうれしくなってキタ。

やったぁ♪ これで「東京都御用達の採点プログラム」に負けないのが作れる☆☆☆
(ハナから相手にされてないのは十分わかってます・・・)

ただ、純粋によくなろうとした自分が久しぶりに愛しい。

3.採点アルゴリズムを改良

で、採点アルゴリズムを次のように改良。なお、採点マークと設問毎の得点の表示設定は、図の「表示」オプションから採点者が選択する仕様。なお、プログラムは、Gridコントロールが空欄である場合、すなわち、入力値がない場合は、答案画像に対する処理は何も行わない。

※ Captionが「種類」となっているRadioGroupがコード内のRadioGroup4。
※ →X,↓Yが表示位置調整用の各ComboBox。矢印は意味を視覚的に伝える工夫。
※ Sizeで採点記号及び得点のFontの大きさを指定。

表示のデフォルト設定は「採点記号も得点も両方表示する」
//Gridコントロールへの入力値がない場合は「何もしない」
procedure TFormCollaboration.StringGrid1DrawCell(Sender: TObject; ACol,
  ARow: Integer; Rect: TRect; State: TGridDrawState);
var
  ・・・ 必要な変数を宣言 ・・・
  //例
  intValue : integer;
begin

  // 以下、実際のプログラムコードから必要な部分のみ抜粋

  if StringGrid1.Cells[ACol,ARow]<>'' then
  begin
    // 誤入力'00'があれば'0'に変換
    if StringGrid1.Cells[ACol,ARow]='00' then
    begin
      StringGrid1.Cells[ACol,ARow]:='0';
    end;

    // 入力文字数が3文字以上なら'0'に変換
    if Length(WideString(StringGrid1.Cells[ACol,ARow])) > 2 then
    begin
      StringGrid1.Cells[ACol,ARow]:='0';
    end;

    // 入力値が「数値」に変換できなかった場合はすべて'0'に変換
    if not TryStrToInt(StringGrid1.Cells[ACol,ARow], intValue) then
    begin
      StringGrid1.Cells[ACol,ARow]:='0';
    end;

    //背景色を白に設定
    StringGrid1.Canvas.Brush.Color:=clWhite;

    //正負をチェック
    if StrToInt(StringGrid1.Cells[ACol,ARow])< 0 then
    begin
      StringGrid1.Canvas.Font.Color:=clRed;
    end else begin
      StringGrid1.Canvas.Font.Color:=clBlack;
    end;

    //セルを塗りつぶす
    StringGrid1.Canvas.FillRect(Rect);

    //テキストを表示(中央寄せ)
    DrawText(StringGrid1.Canvas.Handle,
      PChar(StringGrid1.Cells[ACol,ARow]),
      //[+1]は数値描画位置の調整のため
      Length(StringGrid1.Cells[ACol,ARow])+1,Rect,
      DT_CENTER or DT_VCENTER or DT_SINGLELINE);

  end;

  //Cellの値が0ではなかった場合の処理
  if not (StringGrid1.Cells[ACol,ARow]='0') then
  begin
    //Cellの値が正だった場合(完全正答〇の処理)
    if StrToInt(StringGrid1.Cells[ACol,ARow]) > 0 then
    begin

      //imgAnswerは答案画像を表示するTImage

      //Windows APIのSetBkMode関数でTRANSPARENTを指定
      SetBkMode(imgAnswer.Canvas.Handle, TRANSPARENT);
      imgAnswer.Canvas.Font.Color := clRed;
      imgAnswer.Canvas.Font.Size  := StrToInt(FontSize指定用ComboBox.Text);

      case RadioGroup4.ItemIndex of
        0:begin
          //cmbX, cmbYは表示位置調節用の値を入力するComboBox
          imgAnswer.Canvas.TextOut(DestRect.Left+StrToInt(cmbX.Text),
            DestRect.Top+StrToInt(cmbY.Text), '○');
        end;
        1:begin
          imgAnswer.Canvas.TextOut(DestRect.Left+StrToInt(cmbX.Text),
            DestRect.Top+StrToInt(cmbY.Text), StringGrid1.Cells[ACol,ARow]);
        end;
        2:begin
          imgAnswer.Canvas.TextOut(DestRect.Left+StrToInt(cmbX.Text),
            DestRect.Top+StrToInt(cmbY.Text), '○'+StringGrid1.Cells[ACol,ARow]);
        end;
      end;

    end else begin

      //Cellの値が負だった場合(△)-> この部分を新規に追加
      if StrToInt(StringGrid1.Cells[ACol,ARow]) < 0 then
      begin
        //Windows APIのSetBkMode関数でTRANSPARENTを指定
        SetBkMode(imgAnswer.Canvas.Handle, TRANSPARENT);        
        imgAnswer.Canvas.Font.Color := clRed;
        imgAnswer.Canvas.Font.Size  := StrToInt(FontSize指定用ComboBox.Text);

        case RadioGroup4.ItemIndex of
          0:begin
            imgAnswer.Canvas.TextOut(DestRect.Left+StrToInt(cmbX.Text),
              DestRect.Top+StrToInt(cmbY.Text), '△');
          end;
          1:begin
            imgAnswer.Canvas.TextOut(DestRect.Left+StrToInt(cmbX.Text),
              DestRect.Top+StrToInt(cmbY.Text),
              IntToStr(Abs(StrToInt(StringGrid1.Cells[ACol,ARow]))));
          end;
          2:begin
            imgAnswer.Canvas.TextOut(DestRect.Left+StrToInt(cmbX.Text),
              DestRect.Top+StrToInt(cmbY.Text), '△'+
              IntToStr(Abs(StrToInt(StringGrid1.Cells[ACol,ARow]))));
          end;
        end;
      end;
    end;

  end else begin

    //不正解の場合の処理(×)
    //Windows APIのSetBkMode関数でTRANSPARENTを指定
    SetBkMode(imgAnswer.Canvas.Handle, TRANSPARENT);    
    imgAnswer.Canvas.Font.Color := clRed;
    imgAnswer.Canvas.Font.Size  := StrToInt(FontSize指定用ComboBox.Text);

    case RadioGroup4.ItemIndex of
      0:begin
        imgAnswer.Canvas.TextOut(DestRect.Left+StrToInt(cmbX.Text),
          DestRect.Top+StrToInt(cmbY.Text), '×');
      end;
      1:begin
        imgAnswer.Canvas.TextOut(DestRect.Left+StrToInt(cmbX.Text),
          DestRect.Top+StrToInt(cmbY.Text), StringGrid1.Cells[ACol,ARow]);
      end;
      2:begin
        //chkZeroはCaption「得点0は表示しない」のCheckBox
        if not chkZero.Checked then
        begin
          imgAnswer.Canvas.TextOut(DestRect.Left+StrToInt(cmbX.Text),
            DestRect.Top+StrToInt(cmbY.Text), '×'+StringGrid1.Cells[ACol,ARow]);
        end else begin
          imgAnswer.Canvas.TextOut(DestRect.Left+StrToInt(cmbX.Text),
          DestRect.Top+StrToInt(cmbY.Text), '×');
        end;
      end;
    end;
  end;
end;

で、実行結果は・・・(解答はテキトーなので、それ自体に意味はありません。ここでは+5xを正解で得点4点とし、-5xを△で部分点2点としている)。

採点欄への入力が正の数なら〇、ゼロなら×、負の数なら採点記号は△を表示

今、こうしてコードを眺めて見れば、別に変わったコトなんてなぁーんにもしてない、ほんとに単純なif文のネストにすぎないんだ・・・けど。

ここに、たどり着くまでは、ほんとうに長かったなぁ

あらためて(あたりまえのことですが)、処理の基礎となる考え方・・・アルゴリズムの重要性がわかった気がしました。

こんな、なんでもないような工夫で、自分の中ではかなり大きかった(△マークが使えない)という問題を解決できるんだ。ただ、そこにたどり着くためには、残念ながら、僕にはすごく「時間」がかかるんだ。でも、あきらめずに(時間はかかるけど)出来るまで頑張れば、プロが書いたプログラムと同じことが、僕にもできるんだ・・・って。

多くの人にとって、おそらく、まったく参考にならない、こんなことを、お金までかけて公開するのは、つまり、もしかしたら、どこかにいる、かもしれない、僕と同じような気持ちでいる誰かに、(あきらめないで)って伝えたかったから・・・かも、しれない。

あなたの夢を、あきらめないで・・・って。

4.合計点の計算と印刷

続いて、合計点の計算・その印刷位置の指定から返却用答案画像の印刷へと繋げる部分。まず、絶対値に換算して合計を計算するようにコードを修正。ただ、Abs( )を追加しただけで、あんなに悩んだ△マークの処理が実現できるなんて、なんだか、夢のよう。

var
  i,j,k : integer;
begin
  //合計点を入れる変数kを初期化
  k := 0;
  //合計点を計算
  for i := 1 to StringGrid1.RowCount-1 do
  begin
    for j := 1 to StrToInt(解答欄数.Text) do
    begin
      if StringGrid1.Cells[j,i] <> '' then
      begin
        //△に非対応
        //k := K + StrToInt(StringGrid1.Cells[j,i]);
        //△は負の数で入力しているから絶対値で計算
        k := K + Abs(StrToInt(StringGrid1.Cells[j,i]));
      end;
    end;
    //合計点を保存(StringGrid.Cells[列, 行])
    StringGrid1.Cells[StrToInt(解答欄数.Text)+1, i] := IntToStr(k);
    //合計点を初期化
    k := 0;
  end;
end;

返却用答案画像の印刷にあたっては、合計点表示の有無を選択しないと印刷ボタンをクリックできない仕様として・・・。ユーザーが合計点「有り」を選択した場合は、合計点を上記コードで計算後、返却用答案画像をTImageに表示し、このTImageへのMouseDownイベントを利用して、ユーザーに合計点印刷位置を指示してもらい、合計点入りのサンプル画像を提示(合計点の印刷位置の修正は、ユーザーが納得できるまで何回でも可能)。最終的に位置が決まったら印刷ボタンへフォーカスを移して、クリックで印刷という流れ。

合計点の印刷の有無を指定し、「有り」の場合は必要な処理を行わないと、印刷ボタンはクリックできない。
ユーザーのクリックした位置を左上座標(0,0)として合計点を挿入&返却用答案のサンプルを提示。
(サンプル画像にある矩形は、実際には印刷されない)
「いいえ」をクリックすれば何回でも位置指定のやり直しが可能。

以下のコードが合計点の印刷位置決め部分。「いいえ」を選択した場合は、合計点サンプルを表示したのと同じ場所に、同じ内容を「赤」ではなく、「白」で再描画して消去したように見せかけている(よく見ると若干、先に赤で表示した合計点の輪郭が残っているのがわかる。その原因は不明。今後、原因を調べたい)。

「いいえ」を選択した場合の画像(白で上書きした合計点の輪郭が残ってしまう)
//合計点VCLはLabel
//フォントサイズ指定VCL、解答欄数VCLはComboBox
//変数bSumは、合計点印刷の有無を確認するBoolean型変数
procedure TFormCollaboration.Image1MouseDown(Sender: TObject;
  Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
var
  MyPath : string;
  TempBmp : TBitmap;
  //MessageDlgの押されたボタンを知る
  Ans : Word;
  //BalloonHintの表示
  LTitle : string;
  LText  : string;
  LhIcon : HICON;
  LPos   : TPoint;
  LArrow : TBalloonArrow;

  //普通の四捨五入を行う関数を設定
  function Roundoff(X: Extended): Longint;
  begin
    if x >= 0 then Result := Trunc(x + 0.5)
              else Result := Trunc(x - 0.5);
  end;

  procedure GetXY(iX,iY:Integer);
  begin
    //合計点印刷位置の座標を取得
    iX:=Roundoff(iX/(TrackBar1.Position/100));
    iY:=Roundoff(iY/(TrackBar1.Position/100));

    //Imageに画像をセットする際、自動でサイズ調整を行っている
    合計点の位置X:=iX;
    合計点の位置Y:=iY;

    //矩形を描画
    with Image1 do
    begin
      //Canvas.Brush.Style:=bsClear;  //Pythonを使っていない時はこれでOK!
      //Pythonを使っている時は明示的に書く必要がある
      //(Python.pasにもbsClearが定義されている)
      Canvas.Brush.Style:=Vcl.Graphics.bsClear;
      Canvas.Pen.Color:=clRed;
      Canvas.Pen.Width:=3;
      //矩形を描画
      合計点VCL.Font.Size:=StrToInt(フォントサイズ指定VCL.Text);
      Canvas.Rectangle(合計点の位置X, 合計点の位置Y, 
        合計点の位置X+合計点VCL.Width, 合計点の位置Y+合計点VCL.Height);
      Canvas.Font.Color:=clRed;
      Canvas.Font.Size:=StrToInt(フォントサイズ指定VCL.Text);
      //LabelにStringGridから合計点を取得しておく
      合計点VCL.Caption:=StringGrid1.Cells[StrToInt(解答欄数VCL.Text)+1, 1];
      Canvas.TextOut(合計点の位置X, 合計点の位置Y, 合計点VCL.Caption);
    end;
  end;

begin

  if bSum then
  begin

    //合計点の印刷位置の座標を指定&取得
    //Imageをクリックするたびに、GetXY(X,Y)が呼び出される(実行される)
    GetXY(X,Y);

    Ans:= MessageDlg('印刷位置は、この位置でよろしいですか?'+#13#10+#13#10+
      '(左寄せで印刷。矩形は印刷されません。)',
      mtInformation, [mbYes, mbNo, mbCancel], 0);

    if Ans = mrYes then
    begin

      //[はい]が選ばれた時

      //案内
      MessageDlg('印刷ボタンをクリックしてください。', mtInformation,[mbOK],0);

      //バルーンヒントのタイトルとヒントの内容
      LTitle := '印刷ボタン';
      LText  := 'ココです!' + sLineBreak + 'クリックしてください';

      //バルーンヒントの表示のとスタイル
      LArrow:= baTopLeft;       //VCLの上・左へ向けて表示
      //LArrow:= baTopCenter;     //VCLの上・中央
      //LArrow:= baTopRight;        //VCLの上・右へ向けて表示
      //LArrow := baBottomRight;  //VCLの下・右へ向けて表示
      //LArrow := baBottomCenter; //VCLの下・中央
      //LArrow := baBottomLeft;   //VCLの下・左へ向けて表示

      //バルーンヒントの吹き出しの始点
      LPos:=印刷ボタン.ClientToScreen(Point(Trunc(印刷ボタン.Width div 2), 0));

      //システムのInfoアイコンを使用
      LhIcon := LoadIcon(0, IDI_INFORMATION);

      try
        //引数はタイトル、ヒント、アイコン、表示位置、吹き出しの始点、時間はミリ秒
        BalloonHint(LTitle, LText, LhIcon, LArrow, LPos, 5000);
      finally
        DestroyIcon(LhIcon);
      end;

      //カーソルを元に戻す
      Screen.Cursor:=crDefault;
      Image1.Visible:=False;
      Image1.Picture.Assign(nil);
      //SetFocus
      印刷ボタン.Enabled:=True;
      印刷ボタン.SetFocus;
    end;

    if Ans = mrNo then
    begin
      //[いいえ]が選ばれた時
      with Image1 do
      begin
        //Canvas.Brush.Style:=bsClear;  //Pythonを使っていない時はこれでOK!
        //Pythonを使っている時は明示的に書く必要がある
        //(Python.pasにもbsClearが定義されている)
        //クリック位置に同じ内容を「白で上書き」してサンプルを消去
        Canvas.Brush.Style:=Vcl.Graphics.bsClear;  
        Canvas.Pen.Color:=clWhite;
        Canvas.Pen.Width:=3;
        合計点VCL.Font.Size:=StrToInt(フォントサイズ指定VCL.Text);
        Canvas.Rectangle(合計点の位置X, 合計点の位置Y, 
          合計点の位置X+合計点VCL.Width, 合計点の位置Y+合計点VCL.Height);
        Canvas.Font.Color:=clWhite;
        Canvas.Font.Size:=StrToInt(フォントサイズ指定VCL.Text);
        Canvas.TextOut(合計点の位置X, 合計点の位置Y, 合計点VCL.Caption);
      end;
    end;

    if Ans = mrCancel then
    begin
      //キャンセルが選ばれた時
      //カーソルを元に戻す
      Screen.Cursor:=crDefault;

      //その他の処理

    end;
  end;
end;

5.まとめ

数値のみを用いて、〇・△・× を表現する。解決までに2ヶ月近くを要した課題だった。最終的には、「Gridコントロールへの入力が、正の数なら〇、負の数なら△(マイナス記号はフラグとして利用)、0(ゼロ)なら × 、空欄なら何もしない。」として解決。

この単純なアルゴリズムにたどり着くまで、僕はあきらめかけたり、再びチャレンジしたり、様々に思い悩んだ。夢見た通り、プログラムはよくなったが、果たして僕自身は成長したのだろうか・・・

僕は天才でも、なんでもない。
特別なことなんて何一つできない。
他の誰かより優れたモノなんて
何ひとつ、持たない・・・。

何をやらせてもトロいし、
物事の理解にかける時間は、ヒトの何倍も必要だけど、
でも、時間さえかければ、
僕にも、かたちにできるものは、ある・・・

いつか、TVで見たんだ。

若き日の山中 伸弥先生が、利根川 進先生に質問してた。
「日本では研究の継続性が大切だと言われますが、先生はどうお考えですか?」 と。

利根川先生は即答してた。
「重要で、面白い研究であれば何でもいいじゃないか」と。

人々に、社会に、貢献「したか・しなかったか」が、すべてなんだと。

RFKも、同じ言葉を残してる。

The purpose of life is to contribute in some way to making things better.
「人生の目的は、ものごとを良くすることに対してなんらかの貢献をすることだ。」

さらに・・・

You’re happiest while you’re making the greatest contribution.
「最高の貢献を成そうとする時、あなたは最高の幸福を知る。」

とも(命の使い方を、彼自身の人生が代弁している気がするけど・・・)。

ようやくカタチにできた、僕の夢を、
職場のみんなに自由に使ってもらえるプログラムとして公開する。
たったひとり、でもいい。
このプログラムでしあわせを手にする人が、どうか、いてほしい。

それをもし、貢献と呼んでもらえるなら、
どんなにか、うれしいだろう・・・

そして、僕がこの世界から消えた後まで、
これまでにかたちにしたいくつかの夢を・・・もし、残せたら
どんなにか、しあわせだろう・・・

Delphiといっしょに、
Object Pascalで組んだ、
夢のかたち。

そう、夢のかたち・・・。

この胸にずっと、思い描いてきた
僕の夢のかたちを。

6.お願いとお断り

このサイトの内容を利用される場合は、自己責任でお願いします。ここに記載した内容を利用した結果、利用者および第三者に損害が発生したとしても、このサイトの管理者は一切責任を負えません。予め、ご了承ください。