月別アーカイブ: 2024年3月

無料で使える手書き答案採点補助プログラム

Answer Column Reader

横書き答案の採点実行時の画面です。


スキャナーで読み取った手書き答案のJpeg画像から、大問1の設問(1)なら(1)のみを抽出、一覧表示してイッキに採点。採点記号( 〇・△・× )& 得点付きで元の答案画像に書き戻し、最後に得点合計を自動計算、指定位置に描画して、返却用答案画像(A4サイズに統一/縦・横の指定は可能)を印刷できる無料の手書き答案採点補助プログラムです。

一般的な横書き答案に加え、国語で使用される縦書き答案の採点も可能です。

縦書き答案の採点実行時の画面です。


新教育課程の観点別評価にも対応。もちろん、表計算ソフトを使わずに成績一覧表の作成・印刷・CSVファイルへの出力が可能です(ただし、成績一覧表の出来栄えは、メモ程度)。

画像処理に使用しているPython用OpenCV関連のファイルサイズが巨大ですが、このファイルサイズを許容していただければ、採点現場で十分使えると(複数の高校で使用中)評価していただけました!

もちろん、完全無料。ただし、動作保証は一切ありません。作成者(僕)は開発環境のDelphi(Object Pascal)の大ファンで、この他にも自作のマークシートリーダーなどを開発・このblogの過去記事で公開していますが、学問領域で評価の対象となるようなプログラミングに関しては全くの素人です。ですから、このプログラムのご使用に際しては、あくまでも素人が趣味で作ったものであるということを十分にご理解いただき、ダウンロードから展開・実行までALL自己責任でお願いします(有償販売禁止の他は、それが唯一の使用条件です)。発見できた不具合はすべて改良改善しましたが、取り切れていない未発見の不具合もまだきっとあると思います。それでも、もし、よろしければお使いください。僕の夢のカタチ、Answer Column Reader。

手書き答案採点補助プログラム、名付けて AC_Reader です。

【もくじ】

1.使い方
(1)zipファイルを展開
(2)プログラムを起動
(3)スキャンした答案の画像を準備
(4)採点用画像の準備
(5)解答欄の座標を取得
 ・【座標データを追加したい場合は?】
 ・【字数制限のある解答欄座標の簡単な取得方法は?】
 ・【機械が認識しやすい解答欄】
 ・【生徒の番号・氏名も解答横に表示して採点したい】
(6)採点
 ・【全員正解を入力】
 ・【全員不正解を入力】
 ・【個別に採点】
 ・【次の設問を採点】
 ・【定型文を入力】
 ・【入力した定型文の削除・消去方法】
(7)採点状況の確認
(8)返却用答案の印刷
(9)成績一覧表の作成・印刷
2.まとめ
3.お願いとお断り

1.使い方

もくじへ戻る

(1)zipファイルを展開

ダウンロードしたzipファイルをデスクトップ上に展開します(任意の場所に置いても動作すると思いますが)。PCによっては展開(解凍)に20分程度かかることがあるようです。

もくじへ戻る

(2)プログラムを起動

展開されたフォルダ内に「AC_Reader.exe」があります。これをダブルクリックしてプログラムを起動します。

このアイコンをダブルクリックしてプログラムを起動します


初回起動時には、次のメッセージが表示されると思います。その場合は「詳細情報」(画像中、赤い枠で囲んで示した部分)をクリックします(プログラムの発行元が不明である場合に、Windows のDefender機能である SmartScreen がこの表示を出すそうです。自分の責任で実行すれば、次回からこのメッセージは表示されなくなります)。

「詳細情報」をクリックします。


すると、次の画面が表示されます。「実行」(画像中、赤い枠で囲んで示した部分)をクリックしてプログラムを起動してください。

「実行」をクリックします。


プログラムの起動時に、次のメッセージが表示されます。「はい」・「いいえ」のいずれかを選択してください。

差し支えなければ「はい」を選択してください。


Excelの採点シートを使って処理する場合は、拙作マークシートリーダーとこの手書き答案採点補助プログラムを併用することも可能です(その方法についての説明は、今回は行いません)。

マークシート方式と併用することも可能ですが、今回は「はい」をクリックしてください。


国語の試験では縦書きの解答用紙が使われますので、この手書き答案採点補助プログラムも縦書き答案の採点が出来るよう設計しました。デフォルト設定の答案書式は「横書き」です。国語の縦書き答案を採点したい場合はここで設定画面を開き、縦書きを指定してください。

今回は「いいえ」で先に進みます。


ちなみに「はい」を選んだ場合は・・・

答案の書式を指定できます。


答案の書式の設定変更を起動時に問われなくするよう設定できます。

採点する答案の書式が決まっている場合は「はい」を選択してください。


試験は毎日行われているわけではなく、定期考査として2~3か月に1回実施されるのが普通です。これくらい間が空くと、△の付け方などをどうしても忘れてしまいます。「忘れた!」と毎回のように質問がありましたので、プログラムの起動時にメッセージとして、採点方法を表示することにしました。

特に「△」の入力方法を問われることが多かったです!


この入力方法の案内は、画面右下の「終了」ボタンのとなりにある「入力方法のご案内」ボタンをクリックすれば、いつでも再表示できます。

入力方法はいつでも確認できます。

もくじへ戻る

(3)スキャンした答案の画像を準備

答案の画像は必ず「解像度200dpi程度」でスキャンし、「Jpeg画像として保存」してください。

重要 白黒の二値化画像としてスキャンしないでください。

なお、答案をスキャンする際は、次のことにご注意ください。

・答案が出席番号順に並んでいることを必ず確認してください。
・答案の向きは問いませんが、上下が揃っていることを必ず確認してください。
・試験を欠席した生徒がいる場合は、そこに未使用の解答用紙を挿入しておきます。
・消しゴムの屑等はよく払い落としておきます。
・一度に採点できる枚数は100枚を想定しています。
・答案に折り目がある場合は、なるべく平らになるよう折り戻しておきます。

スキャンした答案の画像は、科目名とクラス・講座名がわかるよう適切な名前をつけたフォルダ内に保存し、このフォルダをAC_Reader.exeがあるフォルダの「ScanData」フォルダにコピーしてください。

重要 スキャンした画像は、必ず「ScanData」フォルダ内にフォルダを作成し、保存してください。

重要 ScanDataフォルダ内のフォルダに階層構造を作らないでください。

よい例:

ScanData¥数学Ⅰ_1A

わるい例:

ScanData¥1年¥数学Ⅰ_1A

もくじへ戻る

(4)採点用画像の準備

上記の手順で、スキャンした答案のJpeg画像を所定の場所に準備したものとして説明します。

プログラムの画面右上にある「画像変換」ボタンをクリックします。

重要 採点用画像には、必ずこの画像変換プログラムが生成したJpeg画像を使ってください。それ以外の方法で作成した画像は使用できません!


次のWindowが開きます。「選択」をクリックしてください。

ScanDataフォルダ内に用意した「答案画像を入れたフォルダ」をクリックして選択します。
練習では予め用意されているSampleフォルダを選択してください。

重要 選択するのは「フォルダ」で、「ファイル」ではありません。

採点したい答案画像のあるフォルダをクリックすればOKです。
(ダブルクリックして開ける必要はありません)

サムネイル表示を見て、画像の回転の有無・回転方向を指定します。Sampleの画像で練習する場合は「なし」を指定してください。

次に画像のリサイズの有無を指定します。複合機のスキャナーを使用し、解像度200dpiでスキャンした画像の場合、80%程度に縮小すると採点しやすいと思います。答案画像をプレビューして縮小率を確認しながら作業することができます。

画像のリサイズ設定を行ったら、次に採点用画像の保存先を指定します。「参照」ボタンをクリックしてください。画像の保存先を選択するWindowが表示されます。

採点用画像の保存先は、ScanDataフォルダ内ではなく、「ProcData」フォルダです。

Procはprocessed(処理済み)の略です。

重要 ProcDataフォルダ以外の場所は、作業フォルダに出来ません!

画像の変換元として選んだScanDataフォルダ内のフォルダと同じ名前のフォルダを、プログラムはProcDataフォルダ内に自動的に作成します。ここでは、この自動的に作成されたSampleフォルダをクリックして選択し、OKをクリックしてください。

フォルダは自動的に作成されたものを選びます。

「変換実行」ボタンをクリックすると採点用にリサイズされた画像が上で指定したフォルダ内に作成されます。この処理はGDI+で書きましたので、それなりに高速だと思いますが、答案の枚数が多く、回転を伴う場合は少し時間がかかります。処理が完了するまでしばらくお待ちください。

この処理では用途の異なる2種類の画像を作成します。一つは採点マークのない各解答欄画像の読み取り元として利用する画像、もう一つは採点マークその他必要事項を上書きした返却用答案画像として利用する画像です。このようにすることで、何度でも採点のやり直しができる仕組みを実現しています。

注意していただきたいのは(めったにないことですが)、採点結果を答案画像に書き戻している最中に何らかの原因でプログラムが落ちた(クラッシュ/フリーズ)場合です。プログラムは採点結果を数値データとしてCSVファイルに書き込むと同時に、採点マークを付けて返却用答案画像にも書き込みます。CSVファイルへのデータの書き込みは一瞬ですが、返却用答案画像への書き込みには少し時間がかかります。したがって、この書き込み処理の最中にプログラムが落ちると、確かに採点した(採点データを保存したCSVファイルが存在する)のに、採点結果が正しく書き込まれていない答案画像が出来てしまうといった現象が起こります(過去1回だけ、この現象を確認しました)。このような場合には、それを発見した時点で採点済みのデータを読み込んで、再度(画像への)「書き込み」処理を実行すれば不具合を解消できます。

変換が終了すると、そのことを知らせるメッセージが表示されます。メッセージのOKをクリックすると注意のメッセージが表示されます。この注意のメッセージを確認した後、「終了」ボタンをクリックして、画像変換処理を終了してください。

終了をクリックして、この窓を閉じます。

メッセージの「OK」をクリックすると表示されるメッセージです。

画像のリサイズを行った場合は、その際設定した縮小率を試験で使用した解答用紙の残部などに必ずメモしてください。複数クラスで様式の異なる解答用紙を使って試験を行い、それぞれに74%、87%など細かな値を指定した場合は2日も経てばかなりの確率でその値を忘れます。この値を忘れた場合には、採点設定作業をすべてやり直すことになります。十分注意してください。

もくじへ戻る

(5)解答欄の座標を取得

次に解答欄の座標を取得します。その際、重大な注意事項があります。

重要 実際に試験で使用した解答用紙の画像を使用する

わるい例:
・輪転機で大量に印刷した解答用紙でなく、PCからプリンターに出力した解答用紙を使用

上のわるい例のように、実際に試験で使用した解答用紙とは異なる印刷環境で作成した解答用紙は、解答欄座標の取得には使用しないでください。見た目はほとんど同じでも、ほんのわずかな印刷位置のずれが採点作業のすべてに悪影響を及ぼします。この点には、どうか十分にご注意願います。

最初に開発したバージョンでは、拙作マークシートリーダーと同じように解答用紙に座標原点とするマーカー画像を設け、OpenCVのテンプレートマッチングの機能を利用して、マーカー画像からの距離で解答欄の座標を記録し、解答欄矩形の選択に利用していましたが、解答欄矩形を自動的に認識する方法を学んでからは、マーカー画像を利用し、手動で一つ一つ解答欄矩形を指定するよりも、解答欄矩形を自動認識して採点対象とする矩形の座標データのみを取捨選択して保存した方が、実際の採点に入るまでの準備作業時間を大幅に短縮できることがわかりました。また、輪転機を使用して印刷した解答用紙自体に解答欄の印刷位置のずれはほとんど生じないことも、マーカー画像を利用した解答欄座標の取得から、解答欄矩形を自動認識する方向へ設計を変更する大きな要因となりました。

以上の理由からご理解いただけると思うのですが、この手書き答案採点補助プログラムで使用する解答用紙は「解答欄の印刷位置がすべて揃っているもの」でなければなりません。

前置きが長くなりましたが、その具体的な方法は次の通りです。

最初に画面右上の「採点作業」ボタンをクリックしてください。


以前に使用した採点設定ファイルが見当たらない場合は、次のメッセージが表示されます。

よく読んで、OKをクリックしてください。


以前に使用した採点設定ファイルがある場合は、次のメッセージが表示されます。


使用する採点作業の入力欄に下の例のように入力します。

例:R06_考査①_物理基礎

前の方が見えませんが・・・

重要 採点作業の名称にはクラス名を入れないでください。

同じ採点作業の設定を複数クラスに適用する際、採点作業名に特定のクラスの名称が入っていると、なんとなく違和感を感じませんか?(僕は違和感を感じました)

このプログラムでは、(同一問題で実施した)試験の答案をクラス・講座毎のフォルダに準備して、同じ(一つの)採点設定をそれぞれのクラス・講座に適用して採点します。したがって、採点作業の名称には「クラス名を入れない」ことが望ましいわけです。※ クラス名が入っていても採点作業に使えないわけではありません。

採点作業名を付けたら、入力欄の右側にある「Auto」ボタンをクリックしてください。

ほんとうは「解答欄矩形の自動選択」のような名称にしたかったのですが、スペースが・・・


次のメッセージが表示されます。よく読んでOKをクリックしてください。

AC_Readerとは別に、解答欄矩形を見分けて自動選択するプログラムが起動します。このプログラムもObject Pascal に埋め込んだ Python Script で Python 用の OpenCV の機能を利用して動作します。

重要 RectangleDetector.exeを直接起動しないでください

重要 矩形検出機能はAC_Readerから呼び出して使ってください

解答欄矩形を認識するプログラムの名称は「Rectangle Detector(長方形検出器)」です。最初に画面左下にある「画像選択」ボタンをクリックしてください。


ここではフォルダではなく、「ファイルを選択」するダイアログボックスが表示されます。どれでもよいのですが、欠席者がいる場合は、解答欄に何も書き込まれていない欠席者分の解答用紙の画像を選択した方が、誤検出は明らかに減ると思います。ファイルを選択したら「開く」ボタンをクリックしてください。

重要 ここではフォルダではなく、ファイルを選択します。

重要 実際の試験で使用した解答用紙の画像で作業します。

練習では、添付したSampleフォルダ内のファイルを選択してください

解答用紙の画像が表示されます。上下のスクロールバーを操作して、図のように解答用紙の解答欄の直線部分とRectangleDetectorの画面枠の二つを見比べやすい位置に画像を上下に動かして、解答用紙が大きく傾いていないことを確認します。

スキャナーによっては、その機材特有の「クセ」のようなものがあり、どれほどきちんと解答用紙をセットしても必ず0.3~0.4°くらい読み取った画像が傾いてしまう場合があります。サービスマンの方に相談したところ、「答案に付着した消しゴムの屑がローラー等に詰まって、読み取り結果に悪影響を及ぼしているのではないか?」との意見をいただき、実際、スキャナーの可動部をきれいに清掃して試したところ、読み取り結果が改善された経験があります。しかし、その後、またすぐにその機材で読み取った画像は同じ方向に傾くようになりましたので、毎回クリーニングする必要があるのかもしれません。ただ、可動部をクリーニングしなくても、ほとんど傾かずに読み取ることもあり、結局、「これは運だ!」と割り切って、プログラム側で傾きがあった場合は修正できるよう、傾き補正の機能を追加しました。

傾き補正の機能を追加する際に気づいたのですが、回転させた画像をさらに回転させると、画像の質が著しく劣化し、これを繰り返すほどに全体がぼやけて、解答の読み取りに支障をきたす恐れがあるように感じました。そこで、画像の初期状態を保存しておき、回転は必ず初期状態のものに対して行うようプログラミングしました。「なぜ、少しずつ連続して回転させることができないのだろう?」と疑問に思われる方もいらっしゃるかもしれませんが、これがその疑問への回答です。

赤線部分を見比べて、画像の回転の要/不要を判断します。


上の画像のような状態であれば、傾きの補正は必要ありません。オプションボタンは「実行」をクリックして選択してください。また、あまりにも小さな矩形は「解答欄ではない」と判断できるよう、矩形の面積閾値を設定してあります。こちらはデフォルト設定700のままでお試しください。

傾きの修正が必要な場合は「試行」を選択し、修正量を確認してください。
修正量を確認後、その値で傾きの補正を「実行」してください。
(「試行」を選択した場合は、最終的なデータの保存ができません)


続けて答案の「横書き・縦書き」を指定します。Sampleは横書き答案ですので、オプションボタンは「横書き」をクリックして選択してください。


ブロックというのは(表現に苦しんだのですが)、「解答欄の集合をブロックとして見分けられるか・どうか」という意味です。下の図のような解答用紙の場合、1ブロックと表現しています。


ちなみに、次のような場合が2ブロックです。ご理解いただけましたでしょうか?


傾きの修正が必要な場合は、次のGUIで操作してください。「傾き修正」に✅を入れて、▲は修正値を増やす(回転方向は時計回り)、▼は修正値を減らす(回転方向は反時計回り)、「適用」は回転の実行、「やり直し」は画像を初期状態に戻します。


解答欄を取得する準備が整ったら、「解答欄取得」ボタンをクリックしてください。


誠に心苦しいのですが、PCによっては初回実行時、Python Engineの初期化に異常に時間がかかることがあります(職場のPCでは4分程度)。自分のPC(Panasonic製 Let’s note CF-QV)では数秒で終了する処理がなんでPCによってはとんでもない時間を要する処理になるのか? その理由は未だにわかりません。

とにかく、マウスカーソルが砂時計?表示になっていればプログラムは正常に機能していると思われますので、5分程度お待ちください。いったんPython Engineの初期化に成功すれば、プログラムを終了しない限り、2回目以降の実行は何の問題もなく、ほんの数秒で解答欄座標の取得が完了するはずです。

参考 横書き答案の場合、解答欄矩形の座標はx軸方向については左から右へ、Y軸方向については上から下へという順番で読み取ります。

参考 縦書き答案の場合、解答欄矩形の座標はx軸方向については右から左へ、Y軸方向については上から下へという順番で読み取ります。

ただし、解答用紙の画像が右肩上がりに傾いていた場合、Y軸(上下)方向の座標の上下関係から、より値の小さな(座標原点0,0は解答用紙画像の左上であるため)上の方をプログラムは先に読み取ってしまいます。そのため、横書き答案であっても解答欄矩形の読み取り順が右から左になる現象が発生します。こうなると解答欄矩形の座標の選択作業が著しく煩雑になってしまいます(解答欄矩形の座標自体は読み取れていますから作業ができないわけではありません)。これを防止するために、最初に答案画像の全てに対し、傾きの修正を行う必要があります。

解答欄座標の取得が完了すると、次の図にあるように解答用紙上に赤い矩形が描画されます。小さくてわかりづらいかもしれませんが、画面右上の解答欄座標の値が表示されている部分で、カーソルがある(カーソルが点滅している位置の)解答欄座標が赤の矩形で示されています。ここから必要な座標と、いらない座標を取捨選択する作業を行ってください。


上の図で示されている矩形(座標)は採点には不要です。このまま無視して次へ進んでも構いませんし、面倒でなければ不要な座標は削除することもできます。


「編集」ボタンをクリックすると、キャプションが「編集中」に変わり、カーソル位置の座標が選択された状態になります。DELキーを押し下げして、不要な座標を削除します。

次の図は(削除作業を行わずに)上の図の状態から↓矢印キーを1回押し下げして、カーソルを2行目に移動させた状態を表しています。不要な解答欄座標の削除作業を行った場合は、自動的にこの状態になります(1行目にあった不要な座標は当然消えています)。

カーソルを下の行へ移動させて、解答欄矩形のみを選択(移動)して行きます。


2行目の座標が示す矩形はまさに解答欄ですから、これは必要な座標ということになります。このような座標は「移動」ボタンをクリックして、必要な座標ばかり集めたメモの方へ移動させます。次の図は2行目の座標を移動させた直後の状態です。

必要な解答欄座標のみを選択します。

下向きの矢印キーを押す。必要な座標であれば「移動」ボタンで下のメモに移動する。この作業を繰り返して採点する順番になるよう、解答欄の座標をすべて取得します。次の図は一通り、解答欄の座標を取得した状態です。


続いて正しく解答欄座標が取得できていることを確認します。上の図の移動済み解答欄座標が表示されているメモ(赤枠内)の先頭の座標データをクリックしてください。メモは必要であれば上にスクロールしてください。メモの先頭の座標データをクリックしたら、答案の画像も上にスクロールしてください。画面は、次の図のようになります。

メモ内のフォーカスがある座標データに該当する矩形が赤枠で示されています。


このまま、下向きの矢印キーを次々に押し下げして、赤枠で示される解答欄矩形が必要数あるか・どうか、及び、採点順に並んでいるか・どうかを確認して行きます。

もくじへ戻る

【座標データを追加したい場合は?】

様々な事情から、座標データを後から追加・変更したい場合もあるかと思います。例えば、次の図のように青枠で囲った解答欄AとBを抱き合わせて採点(両方正解で〇等)したい場合です。

青枠部分を抱き合わせて採点したい場合も当然あるかと思います。


このような場合は、該当の座標データの「末尾」にフォーカスした状態で(=座標データの末尾にカーソルを置いて)、「移動」ボタンの隣にある「追加」ボタンをクリックし、さらにEnterキーを1回押し下げして改行します。次の図は、その状態を示します。

「追加」ボタンのキャプションは「追加中」に変わります。


次に、画面の真ん中よりやや右にある追加ボタンをクリックします。


答案画像の上に赤枠の矩形が表示されます。この矩形を新しく解答欄座標を取得したい解答欄に重なるように移動・変形してください。矩形を移動させたい時は、矩形の上の横線中央よりやや右の位置をポイント(マウスのカーソルを載せる)すると、マウスカーソルが上下左右の白い矢印に変わり、ドラッグアンドドロップできる状態になります。

任意の座標を取得可能です。


抱き合わせて採点したい解答欄を矩形で囲んだら(下の図のような状態)、キャプションが「取得」に変わったボタンをクリックします。すると、ボタンの右側に、現在表示されている矩形の座標が表示されます。同時に、この矩形データはクリップボードにも送信されています。


続けて、右側のメモ内の先ほど改行して空行になっている箇所をクリックしてCtrlキーを押しながらVキーを押す(右クリックして表示されるサブメニューから「貼り付け」を選択)等して、取得した座標データを付け加えます。正しくメモに追加できたら、メモの上の「追加中」ボタンをクリックして、キャプションを「追加」に戻します。

上下の矢印キーを押して、解答欄Aの座標を探し、「追加」ボタンをクリックして、メモを編集可能な状態に変更、データを削除します。削除後、編集が終了したことをPCに伝えるため、「追加中」ボタンをクリックして「追加」に切り替えます。

解答欄Bの座標も、解答欄Aと同様に作業してメモから消去します。

注意 「追加中」状態で作業しないとエラーが発生します!

もくじへ戻る

【字数制限のある解答欄座標の簡単な取得方法は?】

例えば、次のような多数の細かい枠で構成された字数制限のある解答欄がある場合、このまま矩形座標の自動取得処理を実行すると一つ一つのマス目の座標をもれなく取得・表示してしまいます。

解答欄を構成する枠がすべて実線の場合、解答欄座標の取得が煩雑になります。


このような場合は、解答欄を作成する段階で、外枠のみ実線で描き、内部の枠はすべて「点線」で描くようにします。点線は、色が薄く、間隔の狭い、細い点線でなく、次の図に示すように、色が濃く、間隔が広い、太い点線を使用してください。

解答欄内部の枠を「点線」で描くとプログラムは外側の枠のみを解答欄座標として認識します。


実は、最初の段階からこの「字数制限のある解答欄の認識処理をどうするか?」という問題は大変気になっていたのですが、親しい国語の教員が作成した解答用紙をスキャンして、解答欄の座標を自動取得する作業のお手伝いを行った際、解答用紙の点線部分をプログラムが認識しないことを偶然発見し、大喜びしたというのが本当です。最初から、僕に、そのような知識があったわけではありません。

偶然とは言え、僕の不出来なプログラムの動作を信じて、それでも使いたいと言ってくれた彼女に、心から、ほんとうに、こころから、「ありがとう」です。巡り合ってから、もう、30年になりますが、Sさん、ほんとうに、ありがとう! あなたがいてくれて、ほんとうに、よかった!!

ただし、これは「諸刃の剣」で、何らかの原因で解答欄の枠線の一部が途切れていると、プログラムは正直にその部分は「矩形ではない」と判断して、座標データの取得対象から除外します。ですので、解答用紙を印刷する際は、解答欄が完全に実線で囲まれているか・どうかを、よく確認してから印刷する必要があります。

解答欄の枠線の一部が途切れていると座標を取得できません!

もくじへ戻る

【機械が認識しやすい解答欄】

解答欄を構成する矩形は必要最小限度に留めるのが、解答欄座標を自動認識・取得する作業を効率よく進めるための何よりのポイントです。

解答欄を構成する矩形は必要最小限にしてください。

もくじへ戻る

【生徒の番号・氏名も解答横に表示して採点したい】

重要 横書き答案の採点時のみに利用できる機能です。

こちらは同僚からの要望があって付け加えた機能です。解答用紙の氏名欄の画像を取得して、採点時に該当生徒の解答欄の横(位置の指定も可能)に、試験を受けた生徒の出席番号や氏名を表示できます。「追加」ボタンをクリックして赤枠の矩形を描画・適切な位置へ移動後、解答欄矩形としての「取得」の代わりに、「氏名欄取得」のボタンをクリックして、次の図に示すようなかたちで解答用紙の氏名欄の座標を取得してください。ただし、指定する矩形の高さは、解答用紙の解答欄の高さの最小値を超えないよう、十分注意してください。

重要 「解答欄の高さの最小値を超えない高さ」で範囲指定してください。

座標が空欄でなければ、氏名情報ありとして保存されます。


最後に、取得した解答欄の座標を保存して作業は終了です。画面右にある「保存」ボタンをクリックしてください。


次の確認メッセージが表示されます。

「はい」をクリックして、解答欄座標を保存します。


採点作業名として設定した名称で、イニシャライズファイルが作成されています。この採点作業名をクリックするとダイアログの下のファイル名が採点作業の名称に変化します。この状態で「保存」ボタンをクリックしてください。

採点作業名を設定した際にiniファイルも作成されています。
解答用紙の種類に合致するファイルをクリックして選択・上書き保存します。


次のメッセージが表示されます。「はい」をクリックしてください。

既存のiniファイルに上書きします。


解答欄の数によっては、少し(数秒程度)時間が必要です。保存作業が完了すると次のメッセージが表示されます。このメッセージが表示されるまで、何もしないでそのままお待ちください。


画面右下隅にある「閉じる」ボタンをクリックしてプログラムを終了します。解答欄矩形の座標の候補を表示する上のメモにデータがある場合は、「閉じる」をクリックすると、次の確認メッセージが表示されます。「はい」をクリックしてプログラムを終了させてください。


以上で、解答欄の座標の取得作業は完了です。

もくじへ戻る

(6)採点

解答欄座標取得後、すぐに採点を実施する場合は、タスクバーにAC_Readerが眠っていますので、クリックして起こしてください。そうでない場合は、AC_Readerを起動してください。

解答欄矩形取得直後、AC_Readerはタスクバーに眠っています。
タスクバーにある上のアイコンをクリックしてください。
AC_Readerが目覚めます!


画面の右上にある「採点作業」ボタンをクリックしてください。


次のメッセージが表示されます。既存の採点設定を利用して採点しますので「はい」をクリックしてください。


バルーン型のヒントが表示されます。V マークをクリックして表示される選択肢から採点設定ファイルを選んでください。


採点設定ファイルを選んだ直後の状態です。


画面中央には、次のメッセージが表示されます。OKをクリックするとフォルダの選択ダイアログが表示されます。


採点したいクラスのフォルダを選択してOKをクリックしてください。

採点したいクラスのフォルダを選択して、OKをクリックします。


採点結果を記録したCSVファイル(場所はユーザーに提示しません)がない場合には、次のメッセージが表示されます。


画面は次のようになります。

個人識別情報が保存されているので、番号や氏名も表示されています。


画面上方、中央よりやや右に、どこにもドッキングしないフローティング状態の必要最小限の採点機能をまとめたパネルがあります。このパネルのタイトルバーの部分を左クリックしてドラッグ&ドロップすると任意の位置へ移動できます。採点しやすい位置へ移動してお使いください。

もくじへ戻る

【全員正解を入力】

解答をざっと見て、過半数が正解であるような場合は、全員に正解を入力し、後から不正解の解答のみチェックして、採点を × に変更します。

この設問の得点は2点として、全員に2点を入力します。


ComboBoxの選択肢に「2」を指定して、「入力」ボタンを

採点記号の位置や大きさは「設定」から変更できます。


設定画面から、採点記号の表示位置や大きさなど、各種設定を変更・保存できます。

何も変更せず、デフォルト設定のまま、みなさんお使いのようです。

もくじへ戻る

【全員不正解を入力】

フローティングパネルの得点欄に0を設定して、入力をクリックすれば、全員不正解となります。

0(ゼロ)は〇(まる)と見間違える可能性があるため、
デフォルト設定では、不正解の場合、得点0を表示しません。

もくじへ戻る

【個別に採点】

重要 左手で入力作業、右手は選択作業(クリックに専念)

・正解 〇 を入力

まず、個別に採点する際の正解入力は、次のように行います。

解答欄の中心付近をクリックして、得点に相当する数字キーを押します。


解答欄に採点記号〇と得点が描画されます。

・不正解 × を入力

不正解を入力する場合は、次のように操作してください。

× は「Batsu」だから「B」キーに割り当てました。


もちろん、数字キーの0(ゼロ)でも × を入力できます。ただ、0はちょっと位置が遠い・・・

・部分点あり △ を入力

部分点ありの場合は、採点記号△と部分点を入力します。方法は、次の通りです。

「部分点あり」のフラグは「-」記号の有無です。
プログラムは負の数の入力を部分点ありと判定しています。
(合計点は絶対値で計算するので、問題ありません)
部分点ありの場合、採点記号△と得点を表示

重要 最後に「書込」を忘れずにクリックします。

もくじへ戻る

【次の設問を採点】

右向きの三角マークをクリックすると、次の設問の解答欄が表示されます。

上で解説した手順で、採点を行います。

右側の操作パネルからも同じ操作を実行することができます。

もくじへ戻る

【定型文を入力】

記述式の設問等で「ここまで何点」のような定型文を記録しておいて適宜入力できます。

「設定」をクリックして、「入力定型文の編集」にチェックを入れます。


画面左上に次の表示が出ますので、内容を編集します。「記録」ボタンをクリックすると編集内容が保存されます。保存後、「入力定型文の編集」のチェックを外し、編集欄を非表示にします。


定型文を入力したい設問の解答欄を採点します。採点後、定型文を入力したい箇所の左上隅あたりにマウスのカーソルを持ってきて右クリックします。表示されるサブメニューから「定型文入力」を選択(クリック)してください。

重要 採点しないと定型文入力はできません!

「定型文入力」をクリックします。


編集済みの定型文が指定位置に入力されます。

もくじへ戻る

【入力した定型文の削除・消去方法】

入力済みの定型文を削除・消去するには、まず、定型文を削除・消去したい解答欄の真ん中付近をクリックします。次に、右側のGridコントロールの青く反転表示された数値を消去して、Enterキーを押してください。

もくじへ戻る

(7)採点状況の確認

現在の採点状況を、解答用紙全体の画像を表示して確認することができます。次のように操作してください。

画面右側の中ほどにある「返却答案を表示」をクリックします。画面は現在選択されている生徒の解答用紙が表示されます。画面をスクロールして、採点状況を確認してください。


移動のボタンで、別の生徒の答案も確認することができます。

左のボタンで「一枚前へ」、右のボタンで「次へ」移動します。

もくじへ戻る

(8)返却用答案の印刷

採点が終了したら、返却用の答案を印刷します。まず、画面右下のプリンタの選択肢から、出力先のプリンタを選択します。次に「合計の印刷」の有無を指定します。「有」を選択した場合は、次の案内が表示されます。


印刷は採点終了後、最後に実行するので、採点と印刷の処理をお互いに行ったり来たりすることは「ない」と判断し、印刷実行後はプログラムの終了のみ可能となっています。

「いいえ」をクリックした場合は、採点処理が継続されます。「はい」をクリックした場合は、次の案内が表示されます。

出力するプリンタの確認です。


「はい」を選択すると、次に合計点の印刷処理の案内が表示されます。


フォントサイズは、40~50程度が適切な場合が多いように思います。半角の数字で入力してOKをクリックしてください。


OKをクリックすると、次の案内が表示されます。


OKをクリックして、合計点印刷位置を指定します。


クリックした瞬間に自動計算された合計点が指定位置に表示され、次のメッセージが表示されます。


よろしければ「はい」を、位置の指定をやり直す場合は「いいえ」をクリックします。「いいえ」をクリックした場合は、再度、合計点を印刷する位置の指定をやり直してください。その際、前回に指定した位置にゴーストというか、残像のようなものが残りますが、実際の印刷時にはゴースト・残像は印刷されません。

「はい」をクリックした場合は、次のメッセージが表示されます。


画面右下の「印刷」ボタンをクリックしてください。

バルーンヒントが案内します。


「印刷」をクリックすると、次のメッセージが表示されます。


OKをクリックすると、プリンタの設定画面が表示されます。この画面はお使いのプリンタにより異なりますが、重要なチェックポイントは次の3点です。

重要 印刷する用紙がA4版であることを確認する

重要 印刷用紙の縦・横指定を答案に合わせて指定する

重要 両面印刷は必ずOFFに設定する

設定画面を閉じると、次のメッセージが表示されます。


「はい」をクリックした場合は、全員分の返却用答案がプリンタへ出力され、次のメッセージが表示されます。


「いいえ」をクリックした場合は、次のインプットボックスが表示されます。

答案の通し番号を入力してOKをクリックしてください。
採点対象がクラスであれば、出席番号となります。


OKをクリックするとプリンタへ印刷データを送信後、次のメッセージが表示されます。


「はい」をクリックすると、再びインプットボックスが表示され、引き続き単票の印刷処理が継続して行われます。「いいえ」をクリックした場合は印刷処理を終了します。画面右下の「終了」ボタンをクリックして、プログラムを終了してください。その際、次の案内が表示されます。

「はい」をクリックすると、プログラムが終了します。

もくじへ戻る

(9)成績一覧表の作成・印刷

画面右にある「成績一覧表を作成」の「Excelを使わずに作成します!」をクリックします。


画面は成績一覧表作成モードになります。クラス単位の採点である場合は、学年・クラスを指定(選択)します。

重要 予めsNameフォルダに生徒氏名データを用意しておきます。

重要 講座単位の処理の場合も、講座名等で氏名データを準備しておきます。

重要 氏名データの並び順は、答案の並び順と一致させてください。

クラスを指定する場合は、直接入力してください。


講座を指定する場合は、学年・組は「空欄」のまま、「観点区分入力」に進んでください。

設問毎に「知識・技能」は1、「思考・判断・表現」は2を入力します。


観点別評価の区分を入力後、「保存」をクリックしてください。

保存後、「採点結果表示」をクリックして、採点結果の一覧を表示します。

氏名データは架空のもので、得点はダミーデータです。


学年・組を「空欄」で処理していた場合は、ここで「講座等」の名票を選択します。

氏名データは架空のもので、得点はダミーデータです。


次に、合計点が0の生徒について、欠席者であるか(平均点の計算から除きます)・真に0点であるのかを指定する処理を行います。「欠席者を除外」をチェックしてください。


合計点が0の生徒がいる場合は、次のメッセージが表示されます。

試験を欠席していた場合は「はい」を、0点であった場合は「いいえ」をクリックします。
(ここでは「はい」で処理します)


「再計算」ボタンをクリックして、平均点他の再計算を実行します。


プレビューをチェックして、印刷プレビューを表示します。


プレビューをチェックすると、印刷プレビューとともに、次のメッセージが表示されます。

印刷プレビュー画面(氏名データは架空のもので、得点はダミーデータです)


表示されるメッセージ。


プレビューのチェックを外すと、次のバルーンヒントが印刷ボタンを案内します。


「印刷」ボタンをクリックすると、印刷設定のダイアログが表示されます(ダイアログはプリンタにより異なります)。成績一覧表はデフォルトで「A4・縦置き」印刷に設定されます(この設定を変更することはできません)。


OKをクリックすると、印刷データがプリンタへ送信されます。送信が完了すると、次のメッセージが表示されます。


なお、これとは別に、このプログラム用に作成したExcel Book(添付したマクロ有効テンプレートのコピー)へ採点結果を出力し、成績一覧表及び個人成績票を作成する機能もこのプログラムにはありますが、これに関する説明はまた後日、このblogに掲載できたら・・・とも、考えています。が、ほとんど!!どなたにもお読みいただけないであろうMy blogですので、もしかしたらそれは、はるか未来の話になるかもしれません。

ただ、PCの操作及びExcel Bookの扱いに慣れた方なら、このプログラムに添付したマニュアル(以前のバージョンのものなので画面や内容が現行バージョンと若干異なります)と、マクロ有効のExcel Bookの式とマクロをご覧いただければ、操作方法並びに機能の概要はおわかりいただけるのではないかと考えます。

このExcel Bookに対する出力機能は、(ここに掲載した)成績一覧表を独自に作成する機能をこのプログラムに追加する以前に作成し、実際の試験の採点で何回も活用済みのものですが、こちらも動作保証等は一切ありません。もし、お使いになる場合は自己責任でお願いいたします。

以上で、成績一覧表の印刷は終了です。

もくじへ戻る

2.まとめ

今回、掲載した手書き答案採点補助プログラム(新教育課程観点別評価「知識・技能」及び「思考・判断・表現」の評価に対応)の概要は以下の通りです。

【出来ること】

(1)スキャナーで読み取った答案画像から設問ごとに解答欄を抽出して一括採点。
   ※ 答案画像からの解答欄座標の取得は矩形認識プログラムで(半)自動実行。
(2)解答欄画像の隣に受験者氏名等を表示(予め氏名欄等の読み取り設定が必要です)。
(3)記述式の解答に対する定型文コメントの入力。
(4)採点結果を出力した返却用答案画像の作成と印刷(A4版限定・縦横指定は可能)。
   ※ 得点合計を自動計算、返却用答案の指定位置に印刷可。
   ※ B4やA3の答案画像は、A4サイズに縮小して印刷します。
(5)表計算ソフトを使わずに、成績一覧表(教科担任用)を作成。
(6)成績一覧表データをCSVファイルに出力(観点別評価のうち、2観点の評価に対応)。
(7)拙作マークシートリーダーを利用した試験との併用も可。
   ※ マークシートの読み取りプログラム一式も同梱しています。
(8)PDF化した答案画像をJpeg画像化して採点(添付のPdf2Jpg.exeを使用)。

【出来ないこと】

機械学習による手書き文字の認識にも過去にチャレンジ(〇・× 及びカタカナのアイウエオを判定)したことがあるのですが、どう頑張っても認識率が100%にならない(控えめな表現で9割程度は正しく認識するのですが、解答欄からはみ出した文字や、それは「ア」でなく「つ」と「ノ」でしょ!みたいな文字を構成する部品が極端に離れている字?や、大きく傾いた文字は正しく認識できない)ので、残念ですが、この機能は搭載を見送りました。

〇×記号やカタカナ一文字の認識結果を目視でイチイチ確認するのはどう考えても二度手間です。現時点では、ヒトが行った採点結果を機械にチェックさせる方向で活用した方がいいかもしれません。学習モデルの作成については、Pythonを利用した事例がWeb上に読み切れないほど存在しますが、(僕が実験した範囲では)それらよりMicrosoftのLobeで作成した学習モデルの方が高い認識率を示しました。このことについては当blogの過去記事でその例を幾つか紹介しています。ここで紹介した採点補助プログラムには搭載を見送った自動採点機能ですが、僕の実験結果が何かの参考になれば幸いです。

もくじへ戻る

3.お願いとお断り

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

もくじへ戻る

GetPrinterを使用することは推奨されていません

Delphiで印刷のプログラムを書いていて、動作確認のため実行(F9)する際、次の警告メッセージが表示されることに気がついた。

[dcc32 警告] UnitXXX.pas(1858): W1000 シンボル ‘GetPrinter’ を使用することは推奨されていません

以前は「印刷して終了」というパターンでプログラムを作成することが多かったが、いつの間にか、紙への印刷ではなく、「ファイルへデータを出力して終わり」というパターンが普通になった。だから、印刷を実行するプログラムはこの数年間書いた記憶がない。

(印刷関連のプログラムも進化してたんだ・・・)

では、GetPrinterのかわりに何を使えばいいのか、現在、推奨されている方法を調べたが、GetPrinterにかわって推奨されている「はず」の手続き名がわからない。

さんざん悩んだ末、ようやくGetPrinterの引数の型の問題であることに気づく。もしかしたら、同じ問題で悩んでいる人がいるかもしれない・・・。ふと、そんな気がして。

【もくじ】

1.推奨されている「はず」の手続き名は?
2.GetPrinterが2つある・・・
3.まとめ
4.お願いとお断り

1.推奨されている「はず」の手続き名は?

「Delphi シンボル’GetPrinter’を使用することは推奨されていません」をキーワードに検索してみても、現在推奨されているはずの手続き名を知る手がかりになりそうな情報が表示されない。

この段階で、なんとなく前途に暗雲が漂うのを感じ、気分が重くなる。

(この警告の意味は「互換性のために残されている機能を使っている」ってことだと以前どこかで読んだ気がする。推奨されないってことはそれに代わる方法が必ずあるはずなんだけど・・・)

どうしても代替方法を見つけたい気持ちはもちろんある。その反面・・・

(推奨されないだけで、まだ使えるから、とりあえず、このままでいいかぁ・・・)

そう思ってしまうのも、また本当。

Copilotさんに訊ねても、納得できる回答は得られない。

(なんでかな?)

ただ時間だけが静かに流れて行く・・・

2.GetPrinterが2つある・・・

問題解決の手掛かりは思わぬところにあった。それがコレ!

GetPrinterが2つある!


検索しても代替手段の情報が出てこない。ならば(直接入力で)片っ端から探せばいいと考え、既存のGetPrinter手続きをコメントアウトして改行。Printer.getと入力してみると、あろうことか、GetPrinterが2つ表示される。

よく見ると引数の型がPCharとstringで異なっている。

(コレかー!)

おそらく、上の引数がPChar型なのが「推奨されないGetPrinter手続き」で、下の引数がstring型なのが(誰も教えてくれなかったけど、おそらく)「推奨されるGetPrinter手続き」なんだろー。

そんなことを思いながら、変数の宣言に戻って、次のように引数の型を変更。

var  
  //プリンタ設定
  //Device: array [0..127] of Char;
  //Driver: array [0..127] of Char;
  //Port: array [0..127] of Char;
  Device: string;
  Driver: string;
  Port: string;
  DeviceMode: THandle;
  pDevMode: ^TDevMode;

「プロジェクト」⇨「XXXの構文チェック」を実行し、警告のメッセージが消えたことを確認。同時に何か既視感のようなものが・・・

(そう言えば下にSetPrinter手続きもあったはず・・・)

そう思って、そちらを確認すると・・・やはり、

こちらも2つあった!


2つあるのはいっしょでも、よく見ると違いはあって、GetPrinter手続きの方は引数の前にvarキーワードがついてる「参照渡し」だが、SetPrinter手続きの方はそれがない「値渡し」になってる・・・

それに、変数の型を次のように宣言してあっても・・・

var  
  //プリンタ設定
  Device: array [0..127] of Char;
  Driver: array [0..127] of Char;
  Port: array [0..127] of Char;
こちらの引数の型はstring型でもエラーにならない・・・


(なんでかなー?)

MessageBox関数の引数でも同じことを感じたことがあったような・・・。PChar型の変数をstring型の変数に代入する際には、Delphiの場合、自動的に変換されるって理解であってるのかな?

摩訶不思議。

3.まとめ

GetPrinter手続き、SetPrinter手続きは同名の手続きがそれぞれ2つずつ存在し、引数の型がPChar/stringという違いがある。

引数の型がPChar型のGetPrinter手続きを使うと「シンボル ‘GetPrinter’ を使用することは推奨されていません」という警告のメッセージが表示される。

警告のメッセージを消すには、引数の型がstring型のGetPrinter手続きを使用する。

(これでいいのかなー?)

4.お願いとお断り

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

PDFを画像化したい!

PDF文書ファイルをページごとに画像化したくて様々な方法を探し(AND 試し)ましたが、なかなか「コレだ!」と思える方法が見つからず、ほぼ1日を費やして(ダメか・・・)とあきらめかけた、まさにその時、やっと出会えたのが Swanman (id:tales)さんの Blog の次の記事でした。

外部ライブラリ無しでPDFを描画する。

https://lyna.hateblo.jp/entry/20160625/1466783114

「それならWeb上の変換サービスを使えば・・・」というご意見はもっともですが、利用目的が「スキャナーでPDFファイル化した個人情報を含むデータの画像化処理」で、それなりに枚数もあるし・・・どこかのサーバーにアップして・・・というのは絶対に避けたいところです。

Swanman (id:tales)さんのBlogの記事を頼りに、何とか目的を実現することができました。これは、その際行ったことの備忘録です。

【もくじ】

1.FireMonkeyならPDFiumがある
2.WinRT
3.まとめ
4.お願いとお断り

1.FireMonkeyならPDFiumがある

最近、何かを調べる時はCopilotさんにお伺いをたてることが多いです。そこで、今回も早速きいてみました。

自分:
DelphiでPDFを画像化したいときはどうしたらいいですか

するとPDFiumというライブラリがあるとCopilotさんが教えてくれました。ただ、紹介されたのは「PDFium Component Suite for FireMonkey」だったので、どちらかというとWindows専用にVCLコンポーネントを使ってプログラムを書きたい自分的には(FireMonkeyはちょっと・・・)という感じだったのですが・・・、「溺れる者は藁をもつかむ」と、まさにそんな気持ちでありましたから・・・記事に目を通してみることに。

Copilot さんが教えてくれた FireMonkey 用の PDFium の紹介ページはこちら

PDFium – Delphi/C++Builder FireMonkeyアプリケーション向けPDFエンジン

https://blogs.embarcadero.com/ja/pdfium-pdf-engine-for-your-delphi-c-builder-firemonkey-applications-ja/

そこで紹介されていたコードの一部(抜粋して引用)。

  Bitmap := FPdf.RenderPage(0, 0,
    Round(PointsToPixels(FPdf.PageWidth, PixelsPerInch)),
    Round(PointsToPixels(FPdf.PageHeight, PixelsPerInch)));
  try
    Bitmap.SaveToFile(FileName + '_Page' + IntToStr(I) + '.jpg');
  finally
    Bitmap.Free;
  end;

このRenderPageなる手続きが使えれば、目的はカンタンに実現できそう。
それに PDFium はライセンス的にも問題なさそうだし・・・

(VCL版があればなぁ・・・)

ダメ元で探してみるとPDFiumのVCL版を発見。早速、ダウンロード!

ahausladen/PdfiumLib: PDF VCL Control using PDFium

https://github.com/ahausladen/PdfiumLib

大喜びで、使ってみたんだけれど・・・

RenderPageが「なぁーい!」 T_T

なんと、PDFiumのVCL版には RenderPageがありません でした!!

(間違えていたら、ほんとうに、ごめんなさい)

必要なものは全部 uses して、exeと同じフォルダに PDFium.dll も用意したのですが、何か足りないものでもあったのでしょうか?

なら、FireMonkey で書けばいいじゃん!って気持ちにそう簡単にはなれないのが人間です。実は、それなりに頑張ってFireMonkeyでいくつかのプログラムをこれまでに書いてみたのですが、エラーの原因解明に手間取ることが多くて、Windows PCしか使わない自分にとって、無理してまでクロスプラットフォームでプログラムを書くメリットはないように思えてきて・・・やはり、書きなれたVCLの方が自分にはあってる・・・と、どうしても、そう思ってしまい・・・

それに、ここでFireMonkeyにすると、この先もずっとFireMonkeyで書くことに。

現在、書き続けている一連の採点処理用途のプログラムは、すべてVCLで書いてきたこともあり、大変残念ですが PDFium の使用は、ここで断念することに決めました。

2.WinRT

Swanman (id:tales)さんのBlogの記事に紹介されていた Windows Runtime(略称がWinRT)なるものの存在を、これまで僕は知りませんでした。Win32 API なら名前だけは知ってましたが、どうやらそれより新しいAPI であるとのこと。難しいことはわかりませんが、このWinRTでPDFの画像化ができるのであれば、Windowsの機能を使ってそれが実現できるのですから、新規に何かライブラリを追加したりする必要がなく、それこそ理想的です。

ようやく発見したSwanman (id:tales)さんのBlogの記事を読んで、とりあえず、上記の内容だけは確実に理解できました。早速、アップロードされていたユニットとサンプルコードを有難くダウンロードさせていただき、Project2 のサンプルコードを実行(F9)してみました。すると・・・

[dcc32 致命的エラー] PdfDoc.pas(7): F2613 ユニット ‘WinAPI.Foundation.Types’ が見つかりません。


これは困りました。解決方法がまったくわかりません!

(APIだから、もしかしてMicrosoftさんのほうで、ここ数年のうちに何か変更があったのかな・・・)

pas、すなわち必要なユニットはすべてPathの通ったところに置きましたから、これはライブラリ自体が「ない」ということなのかな・・・?

(ない袖は振れないから・・・、ダメもとで外してみようか・・・)

唯一、思いついた解決方法にならない強引な戦法で前進?することに決め、問題の行をコメントアウト。幸い、誰もこのライブラリを参照していなかったようで、「未定義の識別子」エラーは表示されません。これはラッキー!とばかりに、このまま再度、実行(F9)します。

すると・・・、別のユニットでもうひとつ同じエラーが発生。

[dcc32 致命的エラー] WinAPI.Data.Pdf.pas(21): F2613 ユニット ‘Winapi.Foundation.Types’ が見つかりません。


もう、ムチャを承知で無理やり、前進! 前進!!
この行も // コメントアウト。こちらもラッキーなことに「未定義の識別子」エラーは表示されません。これ幸いと、再び、実行(F9)。

このプログラムが動かなくて困るのは僕だけです。他に誰一人、悲しい思いをする人はいません。それだけが唯一の救いです。

結果は・・・

何の問題もなく、
プログラムは無事に動作しました!

開いたPDF文書はページごとにJpeg画像として保存できました☆

PDFファイルの指定ページをJpeg画像として保存できました!


ちなみに Types の他にはどんなメンバーがいるのかと思い、WinAPI.Foundation をコピペして、n の後ろに「 . 」を入力してみると、入力補完機能が表示した選択肢は・・・

Collectionしかありませんでした


もちろん、誰もこのユニットを参照していないことは明らかなので、次のようにしても動作しました。

存在するからusesしてもエラーにはなりません・・・
(usesするとexeの大きさは少しだけ大きくなりました)


(もしかして、必要なユニットがまだ他にあるのかな・・・)

(でも、どこからも参照されていなかったし・・・)

(何で uses されてたんだろー?)


結局、Winapi.Foundation.Types の謎は解けませんでしたが、PDF文書ファイルの各ページをJpeg画像として保存したいという目的は実現することができました。

今回、僕が探した範囲ではDelphiを使ってPDF文書の画像化を実現する方法は、FireMonkeyでPDFiumを使う方法と、このWinRTを使う方法の二つしか見つけられませんでした。したがって、FireMonkeyという選択肢を選ばないのであれば、WinRTを使うこの方法しか、選択肢はありません。

そのような意味で、Swanman (id:tales)さんのBlogの記事にあった情報は大変貴重な情報であると思いました。Swanman (id:tales)さんにこころから感謝しております。ありがとうございました。

3.まとめ

(1)Delphiで、PDF文書の各ページを画像化する方法はある。
(2)FireMonkeyでPDFiumを使用。
(3)WinRTのAPIを使う方法もある(VCLで動作確認/FireMonkeyでの動作は未確認)。

今回の記事を書くにあたって、プログラムの動作確認に使用したPCの環境は次の通りです。

【デバイスの仕様】
プロセッサ 11th Gen Intel(R) Core(TM) i7-1185G7 @ 3.00GHz 3.00 GHz
実装 RAM 32.0 GB (31.7 GB 使用可能)
システムの種類 64 ビット オペレーティング システム

【Windowsの仕様】
エディション Windows 11 Pro
バージョン 23H2
OS ビルド 22631.3296
エクスペリエンス Windows Feature Experience Pack 1000.22687.1000.0

【Delphiのバージョン】
Embarcadero® Delphi 12 バージョン 29.0.50491.5718

4.お願いとお断り

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

マークシートの採点結果通知(個票)及び成績一覧表の作成

ただし、表計算ソフトは使わずに。

マークシートを利用する際、マークをミスなく読み取れたら、次に読み取り結果を適切に処理する作業が待っています。読み取り結果をCSVファイルに出力し、表計算ソフトで作業するのが一般的な処理の流れだと思いますが、表計算ソフトに苦手意識を持つ方が多いのも事実です。

そこでアンケート集計用途ではなく、試験の成績処理用途専用という但し書き付きで、『表計算ソフトを使わない』・『入力作業は必要最小限度に留める』・『作業はほぼクリックするだけでOK!』というコンセプトを決めて、(拙作)マークシート方式で実施した試験の採点結果通知シート(個票)と成績一覧表(教科担任用)の作成にチャレンジ。

完成までにほぼひと月を要しましたが(現場で)動作検証済みの、ここでご紹介する拙作マークシートリーダーへの「後付け」成績処理プログラムが出来ました。

1問1答の採点用途のみに対応(複数マークを抱き合わせて採点する等、複雑な採点方法には対応しておりません)。

【もくじ】

1.採点結果通知シート作成プログラムのダウンロード
2.マークシート画像に採点結果を出力
3.成績一覧表も作成
4.使い方
5.まとめ
6.お願いとお断り

1.採点結果通知シート作成プログラムのダウンロード

今回紹介する採点結果通知シート作成用のプログラム『ReportCard.exe』は単体では動作しません。動作には、下記リンク先に掲載したマークシート読み取り用のプログラム(拙作MS_Reader.exe)が作成したCSVファイル等が必要です。また、動作に必要なフォルダ配置その他の動作環境も、マークシート読み取り用のプログラム用に作成したものをそのまま利用していますので、拙作MS_Reader.exe が動作する環境で実行していただく必要があります。

ここでは採点結果通知シート作成用のプログラム『ReportCard.exe』の動作検証が手軽に行えるよう、Python環境を除いたマークシート読み取りプログラム(最新版Version 1.1.4)に『ReportCard.exe』を同梱する形でダウンロード用zipファイルを作成し、掲載しています。もちろん、過去記事で紹介しているPython環境を組み込めば(・・・と言っても、ダウンロードして解凍したPython39-32フォルダをMS_Reader.exeがあるフォルダにコピペするだけですが)、マーク読み取り部分は、より一層高速に動作します。

Python環境:Python4Delphiを利用して Object Pascal に埋め込んだ Python Script を実行し、Python用の OpenCV でマークシートのマークの有無、マークした番号を読み取ります。(PCによっては)Python Engine の初期化になぜか?すごく時間がかかることもありますが、1回初期化すれば、どのPCでも大変高速に動作します。拙作マークシートリーダーの動作に必要なライブラリをすべてインストールしたプログラム埋め込み用の Embeddable Python 一式が下記リンク先からダウンロード可能です。

この「採点結果通知シート作成」プログラムも、Python環境があれば自動的にそれを利用して動作するように設計してありますが、テストしてみた結果で率直な感想を言うと、やはり初回起動時の(必須)Python Engine の初期化に(PCによりますが)かなり時間がかかる(数分!)ことがあり、僕のPC:Panasonic製Let’s Note CF-QV ではそのようなことはまったく起きませんが、職場で使っているPCではそれが必ず起こります。とにかく Python Engine の初期化に「それなりに時間がかかる」PCでこのプログラムを使う場合は、例えPython環境があっても、起動直後に画面左上の「✅P4D」のチェックを外し、Python環境を利用せずにプログラムを実行していただいた方が良いかもしれません。

【過去記事へのリンクです】

【採点結果通知シート及び成績一覧表作成プログラムのダウンロード】

2.マークシート画像に採点結果を出力

採点結果通知シートのイメージは、こんな感じ(確認画面として表示する手続きは作成しましたが、画像データとして保存する手続きは「その必要なし」と考え、作成しなかったので、これは確認用画面のハードコピーです)。

シートの左上部分を切り取り
シートの右下部分(得点合計等はここに表示)


・・・ですので処理は、採点結果を画面に表示 → そのまま印刷という流れになります。採点の計算は一瞬で終わり、採点画面はすぐに作成できるから、データは保存しません(そもそも保存しておいて、何回も利用するようなモノではないと思いますから)。

まず最初に考えたのは(当たり前ですが)、マーク読み取り結果と配点をマークシート画像に出力(〇の場合は配点=得点となります)し、得点を観点別評価とともにシートの余白(設問番号付近)に表示することです。

正答ならば採点マークと配点(=得点)を表示
不正解の場合、採点マークと配点を表示


採点マークのサイズと水平方向の表示位置は微調整が可能です(ただし、調整結果を保存する機能はありません)。

採点結果の表示位置は、負の数で左・正の数で右に微調整可能

ここで、配点に加え、不正解の場合は正解も表示したくなりました。ただ、記号フォントに縦長の楕円はなかった?・・・と思うので、フォントは好みに応じて選択できるよう、思いつくままにいろいろ設定。

カタチ的には「θ」が最もマークの形状に近い気がします。


ふと、思い立って数字も選べるように設定。

「Num」を選択すると正解のマークの上に数字を表示します


あと、新教育課程では、観点別評価が導入されているので、観点別評価の「知識・技能」は K1、「思考・判断・表現」は K2 として評価の分類も出力できるように設定。正解マークと合わせて表示すると、こんな感じです・・・。

自分的には、コレがいちばん気に入りました!

正解マークの番号を、マークすべき場所に数字で表示する


得点合計と観点別評価ごとの得点合計は(デフォルト設定)シート右下に表示します。もちろん、フォントの大きさは任意の値を設定でき、表示位置は水平・垂直両方向に微調整が可能ですが、こちらも調整後の座標を保存することはできません。


フォントの大きさや表示位置の微調整は、凝り始めたらキリがなくなりそうで、それが表計算ソフトに代わる高い敷居となる可能性(=危険性)を感じ、デフォルト設定で(この程度でまぁいいか?)とユーザーに判断してもらえるよう設定値を調整しました。

すべて控えめな数値を設定しました!
足りない場合は、ちょっと増やせばOKかな?

3.成績一覧表も作成

これがないと採点結果を記録簿に転記し(ここで間違いが発生する可能性があります)、電卓をパチパチ叩いて平均点等を計算するか、一歩進んで、プログラムが出力したCSVファイルを表計算ソフトで処理して、成績一覧表を作成しなければなりません。

転記したり、電卓を使うのは昭和のスタイルだし、働き方改革の流れにも逆行します。CSVファイルを自由自在に操れる方なら、拙作マークシートリーダーには、マーク読み取り結果をCSVファイルに出力する機能を付けてありますから、そちらをご利用ください・・・ってことでOKかな?・・・なんだけれど、「表計算はちょっと苦手で」という方も少なくありません。

PCを使って何かの処理を行うこと自体が、手作業で行ってきた作業を効率よく自動化することに他なりませんから、・・・ほんとうのことを言えば、マークシートリーダーに付属の一機能として最初から成績一覧表の作成機能を付けたかったのですが・・・マークシートリーダー開発当初は、何よりもまず、確実にマークを読み取れることが最重要課題で、それが可能になった時点で実はもう僕自身が(精神的に)ヘトヘトになっていて、(読み取り結果をCSVファイルに出力できれば、あとは表計算ソフトで・・・)みたいな思い(と強い思い込み)があり・・・

新教育課程で導入された観点別評価も、プログラミングして処理するより、表計算ソフトで処理した方がずっと簡単そうに思えたし・・・

同僚からの要望に応え、マークシートリーダーとは別に作成した「手書き答案の採点プログラム」と、マークシートによる解答を併用した採点に対応する場合でも、表計算ソフトは便利だったし・・・

このような諸々の理由から先延ばしになっていた成績一覧表の作成でしたが、2024年、冬、ここで一念発起して、マーク読み取り後の処理に表計算ソフトを一切使わず、ソフトウェアの機能として必要な帳票を出力できるプログラムを書くことに決め、ダミーデータを使って動作確認をくり返し、不具合箇所を発見するたびに少しずつ手直しして、実際に使ってみてどうかという段階にたどり着いたのが、まさに今です。

ただし、どちらかと言えば「採点結果通知シートの方が主」で、成績一覧表は「読めればイイ」程度の、言わばメモみたいなもの・・・表計算ソフトが苦手な方でも、CSVファイルに出力された採点結果を表計算ソフトで開き、得点データを他のワークシートへコピペする作業は可能で、それさえ出来ればあとは協働作業で現場はなんとか動く・・・という勝手な理由で作りは大いに簡素化。

様々な理由から、氏名は「最初の3文字のみ表示」することにしました。
罫線も、横一線のみ。

(氏名と成績はダミーデータです)

ほんとにナイよりマシ・・・というレベルで完成。T_T

プログラムは技術的な知識不足から(だと思うのですが)、罫線が上手く描画されたり、(同じプログラムなのに)PCによっては罫線が予定位置に描画されなかったり・・・。この罫線が上手く描ける場合と、描けない場合の違いがいまだによくわからないのですが、次のようにして無理やり解決?(しましたが、最終的に問題のあるコードは全面的に書き直しました)

【罫線描画問題解決用GUI の勇姿】

CheckBoxとButtonを一つずつ用意


(1)設定 → システム → ディスプレイ設定変更画面の表示を1クリックで行えるボタンを作成。非常の場合は、これで画面の拡大率を100%に戻してもらう。拡大率100%なら確実に予定の位置に描画されるハズ。

・・・と、思ったのですが、結論から言うとこれはダメでした!!

その後、奮闘努力して問題を解決 → (3)へ

ディスプレイ設定を呼び出すコードは1行でOK!

procedure TForm1.btnDispSettingClick(Sender: TObject);
begin
  //usesにWinapi.ShellAPIが必要
  ShellExecute(0, 'open', 'ms-settings:display', nil, nil, SW_SHOWNORMAL);
end;

(2)CheckBoxを利用して「罫線を描画しない」設定を用意する。チェックOFFだと・・・

ある意味では、究極ともいえる罫線問題解決方法。
(これは、ほとんどムチャですな・・・)


(3)罫線の描画に使っていたコードそのものを新たに書き直し、TImage の Canvas と TPrinter のCanvas それぞれに罫線を描画するようにしたところ、罫線が予期しない位置に描画されてしまう問題は解決できました。最初に書いたコードで、(PCにより)罫線が正しく描画される場合とされない場合がある、その本当の理由は未だにわかりませんが・・・

4.使い方

使ってくださる方がいるとも思えませんが、使い方のマニュアルは以下の通りです。

(1)プログラムを起動

「MS_Reader.exe」と同じフォルダにある「ReportCard.exe」をダブルクリックしてプログラムを起動します。

次のメッセージが表示された場合は、「詳細情報」(画像中、赤い枠で囲んで示した部分)をクリックします(プログラムの発行元が不明である場合に、Windows のDefender機能である SmartScreen がこの表示を出すそうです。自分の責任で実行すれば、次回からこのメッセージは表示されなくなります)。

「詳細情報」をクリックします。


すると、次の画面が表示されます。「実行」(画像中、赤い枠で囲んで示した部分)をクリックしてプログラムを起動してください。

「実行」をクリックします。

アメリカでは、採点結果を通知する個票のことを、高校段階までは “Report Card” と呼ぶそうです。Python4Delphiを使用していることを考えると、プログラムの名称に漢字を使用することは、極力、避けたいところです(これは、Pathに含まれる全角文字に関連するエラーに、Pythonスクリプトを書いていて、これまでさんざん悩まされた経験から)。

また、当初、アイコンは濃い目にデザインしたのですが、100 が赤だと目に痛い。そう、痛切に感じた経緯があって、通常アリエナイ色の 100点 をモチーフにしたアイコンにしました。Report Card の文字は、ほぼ読めませんが!「枯れ木も山の賑わい」とお考えいただけたら幸いです。

100 という数字さえ読み取れれば、何をするプログラムなのか?
お使いいただけた方には、わかってもらえるんじゃないかと・・・。

(2)「開く」ボタンをクリックして、ProcDataフォルダ内にある採点結果通知シートを作成したいクラス(or 講座)のマークシート画像を保存したフォルダを選択。

Python環境が利用できる場合は、P4Dに自動的にチェックが入ります。
※ Python Engine の初期化に時間がかかるPCでは、起動時にチェックをOFFにしてください。


選択するのは「ファイル」ではなく「フォルダ」です。


(3)採点結果通知シートを新規に作成する(既存の採点作業の設定ファイルがない)場合は、次の表示が出るのでOKをクリックし、設問数を入力して、画面左に表示されるGridコントロールに必要事項を入力します。


設問数を最初に入力します。


次に、作業の「入力」を選択(オプションボタンをクリック)します。


配点は最も多く設定する値をデフォルト配点として指定(入力)します。


正解とするマークの番号を入力します。

最初だけフォーカスを与えるために入力するGridをクリックしてください。


配点を変更する箇所があれば、正解に続けて入力します。
最後に観点別評価の区分を入力します。「知識・技能」は半角数字で 1 を、「思考・判断・表現」は半角数字で 2 を、それぞれ間違えないように入力してください。

m(__)m:「主体的に学習に取り組む態度」の評価は、この採点システムでは行えません。

観点別評価の入力を行っているところ。


全項目の入力が完了したら、入力に間違いがないことを必ず確認してください。もし、誤りがあれば、ここで確実に発見し、訂正しておかないと・・・、後から大変なコトに・・・。

必要事項をすべて入力し、内容を確認したら採点設定を保存します。

「MySettei.csv」が(上で指定した)マークシート画像のあるフォルダに保存されます。


保存が完了すると、次の確認メッセージが表示されます。

(4)採点ボタンをクリックして、採点を実行します。


表示されている画像の座標情報を記録したテンプレートを選択します。
(テンプレートの作成は、マークシートリーダーで実行)

テンプレート名をクリックして、決定ボタンをクリック。


適切な採点オプションを選択します。


「観点含全部」を選択した場合は・・・

採点記号と配点(正解の場合は得点)、観点別評価の区分を設問番号付近に表示
得点合計と観点ごとの得点合計を右下に表示
空欄と不正解の場合は、正解を表示


前述した通り、正解記号は選択肢から選択して指定できます。

Numを指定した場合は、正解マークの番号が表示されます

(5)画像の切り替え

表示している画像の切り替えはボタンクリックで実行できます。

ボタンは左から順に「先頭へ」・「一つ前へ」・「一つ次へ」・「最後へ」

(6)印刷

「印刷」ボタンをクリックして、採点結果通知シートを印刷します。


クリックすると表示されるメッセージに答えて、全員分 or 個別 印刷のいずれかを選択してください。


用紙の縦横指定を間違えないように注意してください。

(7)成績一覧表の作成

最初に「学年」と「クラス」を選択してください。


選択制の授業等、特別な編成(=「講座」と表現)の名票は出席番号順・氏名のみのデータを予めsNameフォルダ内に分かりやすい名前を付けて、CSVファイルで準備してください。

学年・組は空欄のままにして、「講座名票」ボタンをクリック


ファイルの選択ダイアログが表示されるので、予め作成・保存しておいた講座の名票を選んでOKをクリックしてください。採点結果一覧がGridコントロールに表示されます。

得点等はダミーデータです。


続けて、平均点を正しく計算するため、未受験者の処理を行います。「編集」チェックボックスをチェックしてください。


未受験と思われるデータがある場合、次のメッセージが表示されます。

テストを受験しており、採点結果が0点の場合は「いいえ」をクリックしてください。


得点「0」はすべて未受験として処理した場合、採点結果の一覧は次のようになります。

未受験者のデータを空欄に変更。


「再計算」ボタンをクリックして、平均点等を更新します。


続けてプレビューをクリックするよう案内が出ます。
プレビューをクリックして成績一覧表を表示します(設定はA4・縦、50名/枚で、この設定を変更することはできません)。

なお、受験者数が51名以上の場合でも、プレビュー画面には最初の1枚目の成績一覧表が表示されます。また、任意のページをプレビュー画面に表示する機能は、このバージョンにはありません。

印刷されるデータをプレビュー画面で確認してください。


プレビューに問題がなければ、プレビューのチェックをOFFにして(外して)ください。
印刷ボタンがクリックできるようになります。

印刷ボタンをクリックすると、プリンターへデータが送信されます。受験者数が50名を超える場合は、プリンターへのデータ送信後、印刷最終ページが画面に表示されます。

5.まとめ

今回、拙作マークシート・リーダーのCSV出力を利用するかたちで作成したプログラム(新教育課程観点別評価「知識・技能」及び「思考・判断・表現」の評価に対応)の概要は以下の通りです。

(1)表計算ソフトを使わずに、マークシート方式試験の採点結果通知(個票)を作成。
(2)表計算ソフトを使わずに、マークシート方式試験の成績一覧表(教科担任用)を作成。
(3)マークシート方式試験の成績一覧表をCSVファイルに出力。

6.お願いとお断り

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

0.1ずつ増減したい!

画像をほんの少しだけ回転させるプログラムを書いた。そこでの角度の指定は、最大でも1°未満を想定(整数値だと大きすぎ)。そこで、回転角度の値を指定するTEditへ、キーボードから直接入力する場合は、0.01刻みでのインプットを可能としたが、TEditとTUpDown等の数量を扱うVCLを組み合わせての入力、つまり、マウスで▲・▼マークをカチカチクリックして値を増減させて入力する場合には、TEditに設定する値は「0.01」刻みでは小さすぎるから、「0.1刻みで増減」させようと思った・・・んだけれど、これが難しかった。

いちばんの問題はコレ(差し引きゼロなら、ゼロと表示すること)
整数値なら、なんでもないことなのに・・・

【訂正】 これが難しかった → これが、(僕には)難しかった。

最初はTEditとTUpDownを組み合わせて、これを実現しようとしたが中々上手く行かず、仕方がないから、TEdit1個とTButton2個を組み合わせて、なんとか当初の目的を実現。その後、当初、気がつきませんでしたが、TEditとTUpDownの組み合わせで、Float値を増減させる方法も見つけました。これはその覚え書きです。

【もくじ】

1.TEditとTUpDownでチャレンジ
2.TEditとTButton2個でチャレンジ
3.増減値が0にならない理由
4.コードを修正
5.0.1ずつ増減
6.まとめ
7.お願いとお断り

1.TEditとTUpDown

とりあえず定番と思われるTEditとTUpDownの組み合わせ。

FormにTEditを1つおいて、Textプロパティに0を代入。
TUpDownも1つ用意。

UpDown1のAssociateプロパティにEdit1を設定

Edit1にUpDown1がくっついた!

くっつく位置は左右いずれかを指定できるらしい。

udRightなら右にくっつく

画像の回転が目的だから、とりあえずUpDown1のMaxプロパティは90、Minプロパティは-90に設定。
(実際に使用する値は1°未満の予定)

MInプロパティを0のままにして設定し忘れると、大変なコトに・・・
(負の数が入力できなくなります)

で、Edit1の値を0.1ずつ増減させる「UpDown1Click手続き」を次のように作成。

procedure TForm1.UpDown1Click(Sender: TObject; Button: TUDBtnType);
var
  Value: Real;
begin
  //注意:このコードは、期待通りに動作しません
  Value := StrToFloatDef(Edit1.Text, 0);
  case Button of
    btNext: Value := Value + 0.1;
    btPrev: Value := Value - 0.1;
  end;
  Edit1.Text := FloatToStrF(Value, ffNumber, 1, 1);
end;

実行(F9)して、▲ボタンを3回クリックしたところ

クリック1回目
クリック2回目
クリック3回目

1ずつ、増加してる・・・。

なんでかなーって、ちょっと思ったけど、UpDown1のincrementプロパティを見て納得。

Incrementがデフォルト「1」になってる・・・

足したり、引いたりしている 0.1 はどこに消えたのか・・・?

とりあえず、原因の一つはコレだ☆
やりたいのは「1」ずつじゃなくて「0.1」ずつ増減だから、そう!

Increment プロパティを 0.1 に変えてみた *(^_^)*♪

そしたら、Delphiに怒られた (T_T)

ひー(心の悲鳴)

Incrementプロパティには、整数しか設定できないようだ。

整数・・・ そぉか、0ならOK?
Value(=Editに表示されている値) に 0.1足したり、引いたりしてるから、これでイケる?

Increment 0 を設定 やった! これで完璧だ☆

実行(F9)すると・・・

▲・▼どっちを何回クリックしても「0」のまま・・・

Value + 0.1や、Value – 0.1はどこに消えた?

1.1 とかになってたから、完全に無視されてるわけでもなさそうだけど・・・???

Increment プロパティが整数値指定だとわかった時点で、なんか嫌な予感がしたんだよなー
他にも、Maxとか、Minとか、入力を制限する値(こちらも整数値で指定)もあるし・・・

ここで謎を追いかけて、無駄に時間を使うより、TUpDownは「整数値専用」と決めて、他の方法を試すことに決定。※ 実際、TEditとTUpDownの組み合わせで、小数値の増減も可能です(後述

2.TEditとTButton2個でチャレンジ

Edit2の右に、Buttonを2つ置いて、こんなふうにしてみた。

見た目の美しさは二の次。目標の実現が最優先。

で、コードは Copilotさん に教えてもらった☆ その質問内容と答えのコードがこちら。
(コード部分はコピー可能だったから著作権的な問題はないと判断)

Q:DelphiでTEditの値を0.1ずつ増減するにはどうしたらいいですか?

A:Copilotさんが教えてくれたコード。

procedure TForm1.Button1Click(Sender: TObject);
var
  Value: Double;
begin
  if TryStrToFloat(Edit2.Text, Value) then
  begin
    Value := Value + 0.1;
    Edit2.Text := FloatToStr(Value);
  end
  else
    ShowMessage('Invalid number');
end;

procedure TForm1.Button2Click(Sender: TObject);
var
  Value: Double;
begin
  if TryStrToFloat(Edit2.Text, Value) then
  begin
    Value := Value - 0.1;
    Edit2.Text := FloatToStr(Value);
  end
  else
    ShowMessage('Invalid number');
end;

これなら間になんにも入らず、直接Editを編集してるから、絶対、大丈夫 だろ?
最初からコレでよかったんだ・・・ みたいな気持ちで、コピペして編集し、実行(F9)。

▲をカチカチ、2回クリックしました。イイ感じです!

で、減算(▼クリック)は、初期値が上の 0.2 のところから始めると・・・

クリック1回目。そうそう、それでOK!

次の▼クリックで、値は「0」になるはず。

ところが・・・

クリック2回目。

はぁ? 0.1 – 0.1 = 0.0(ゼロ)になるはずなんだけど・・・
ナニ、コレ?

クリック3回目。これはOKなんだけど・・・

3.増減値が0にならない理由

そうでした。コンピュータは小数の演算が苦手でした。

僕自身、前にさんざん苦しみました。なんで上の計算が「0」にならないのか?

その理由は、次の記事をご参照ください。

Win11の23H2より前のバージョンなら、正しいと思える答えにたどり着くまでGoogle先生に質問を繰り返すのがこれまでの問題解決の定番と言える方法でしたが、今はとなりにCopilotさんがいてくれます。

期待を込めて、訊いてみました。

Q:Delphiで0ではなく、5.54975987041018E-18と表示されます

以下、Copilotさんの返答の概要です。

・浮動小数点数(DoubleやSingle型など)は完全な精度で表現されない。
・これは、すべてのプログラミング言語で共通の問題。
・解決策の一つは、ある閾値(epsilon)よりも結果が小さい場合は 0 と表示。

完全に納得。

Copilotさん、優秀!
ぼく、きみのファンになりました☆

で、以下、Copilotさんが教えてくれた閾値を設定したコードです(コメント文は短縮)。

var
  Value: Double;
  Epsilon: Double;
begin
  Epsilon := 1E-15;  //閾値を設定
  Value := SomeCalculation();  //計算を実行
  if Abs(Value) < Epsilon then
    Value := 0;
  Edit1.Text := FloatToStr(Value);
end;

4.コードを修正

Copilotさんが教えてくれたコードを読んで、「0.0」と表示されるように修正しました。

procedure TForm1.Button3Click(Sender: TObject);
var
  Value: Double;
  Epsilon: Double;
begin
  Epsilon := 1E-15;  //閾値を設定
  if TryStrToFloat(Edit3.Text, Value) then
  begin
    Value := Value + 0.1;
    if Abs(Value) < Epsilon then
    begin
      Value := 0;
      Edit3.Text := '0.0';
    end else begin
      Edit3.Text := FloatToStr(Value);
    end;
  end;

end;

procedure TForm1.Button4Click(Sender: TObject);
var
  Value: Double;
  Epsilon: Double;
begin
  Epsilon := 1E-15;  //閾値を設定
  if TryStrToFloat(Edit3.Text, Value) then
  begin
    Value := Value - 0.1;
    if Abs(Value) < Epsilon then
    begin
      Value := 0;
      Edit3.Text := '0.0';
    end else begin
      Edit3.Text := FloatToStr(Value);
    end;
  end;
end;

ゼロの時は、’0’ではなく、’0.0′ と文字列指定しているところに「こだわり」ました!

5.0.1ずつ増減

上記コードの実行結果です☆(初期値は 0.2)

▼をクリック
▼をクリック
▼をクリック

閾値が効きました☆

逆(▲クリック)も正しく動作することを確認。

【TEditとTUpDownの組み合わせで実現】

TUpDownのMax及びMinプロパティの値(特にMin)を適切な値に設定し、適切なコードを記述することで、TEditとTUpDownというVCLコンポーネントの組み合わせでも 0.1 刻みの選択肢設定が可能であることを確認しました。その方法は以下の通りです。

※ オブジェクトインスペクタで Increment プロパティの値を予め設定しておくという前提で、

【重要】 負数の入力を想定する場合は、TUpDownのMinプロパティの値に適切な負数を設定します!

【重要】 Increment プロパティに 1 を設定 → ▲をクリック → 値が 0.1 ずつ増加

ちなみに Increment プロパティに 2 を設定した場合は、値が 0.2 ずつ増減します。

procedure TForm1.UpDown1Click(Sender: TObject; Button: TUDBtnType);
begin
  Assert(Sender is TUpDown);
  with TUpDown(Sender) do
  begin
    Assert(Associate is TEdit);
    TEdit(Associate).Text := FloatToStrF(Position / 10, ffNumber, 1, 1);
  end;
end;

上記コードの出典は、こちら

Delphi-PRAXiS

https://www.delphipraxis.net/143779-tupdown-floats.html

貴重な情報をご教示くださいましたこと、投稿者様に対し、心より感謝申し上げます。

上のコードを参考に、使っているVCLの名前を指定して、もっと短くして書けば・・・

procedure TForm1.UpDown1Click(Sender: TObject; Button: TUDBtnType);
begin
  Edit1.Text := FloatToStrF(UpDown1.Position / 10, ffNumber, 1, 1);
end;

増減値に 0.1 ではなく、0.2 以上の値を設定したい場合、Increment プロパティの値は予めオブジェクトインスペクタで指定しておいた方が良いようです。

ちなみにオブジェクトインスペクタのIncrement プロパティに設定してある値は「1」のまま、コードで「2」を指定した場合は・・・

procedure TForm1.UpDown1Click(Sender: TObject; Button: TUDBtnType);
begin
  UpDown1.Increment := 2;
  Edit1.Text := FloatToStrF(UpDown1.Position / 10, ffNumber, 1, 1);
end;

実行(F9)してみるとエラーにはなりませんが、最初の▲押し下げ時に 0.2 ではなく、0.1 と表示されます。また、実行(F9)後、最初の▼押し下げ時には -0.2 ではなく、-0.1 と表示されます。それ以降(▲・▼2回目押し下げ以降)は正しく表示(意図した通り表示)されます。

オブジェクトインスペクタのIncrement プロパティに設定してある値が「1」のまま、コードで値を設定・変更する場合は(実行途中での変更はできませんが)FormCreate時に設定しておけば期待通りに動作するようです(もし、違っていたら、ごめんなさい)。

procedure TForm1.FormCreate(Sender: TObject);
begin
  UpDown1.Increment:=2;
end;

procedure TForm1.UpDown1Click(Sender: TObject; Button: TUDBtnType);
begin
  //UpDown1.Increment:=2;
  Edit1.Text := FloatToStrF(UpDown1.Position / 10, ffNumber, 1, 1);
end;

PCの画面で確認すれば、設定状況がわかりやすいと思います。

この設定なら期待通りに 0.2 ずつ増減しました


以上が、TEditとTUpDownの組み合わせで小数値を増減させる方法のまとめです。

6.まとめ

(1)TEditとTUpDownの組み合わせで0.1刻みの数値の増減は可能。
(2)TUpDownで負の数を扱う場合は、Minプロパティの値も適切に設定する。
(3)TEditとTButtonの組み合わせで小数値の増減計算を行う場合は値「0」に注意する。

7.お願いとお断り

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