「画像のクリック位置とグリッドコントロールの連動」
画像を表示したTImageの任意の1点をクリックしたら、そのY座標に応じてStringGridコントロールの適切なセルを選択するようなプログラムが書けないかなー。・・・と思って、実際に書いてみたら、あまりにも簡単に実現できてしまったお話。
1.やりたかったこと
2.作成したプログラム
3.まとめ
4.お願いとお断り
1.やりたかったこと
次のようなGUIのある採点プログラムを作成した。プログラムはスキャナーで読み込んだ複数枚の答案画像から、設問ごとに解答欄をかき集めて表示するもの(答案画像への書き戻しも可能)。で、採点作業をより一層効率的に行うには、各々の解答欄画像をクリックした際、自動的に採点結果を入力するGridコントロールのセルが選択されたらイイなーと思ったことが、この連動プログラムを書こうとしたきっかけです。
2.作成したプログラム
まず、思ったことはTImageのOnMouseDownイベントを利用すればイイ(画像上でクリックした位置のX, Y座標が取得できる)ということです。早速、imgAnswerという名前をつけたTImageをクリックして選択し、OnMouseDownイベントの右側をダブルクリックして、imgAnswerMouseDown手続きを作成。
次のようなコードを書いてみました!
procedure TFormCollaboration.imgAnswerMouseDown(Sender: TObject;
Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
//imgAnswerの高さは、解答欄1つの高さ × 解答用紙数 だから
//クリックした場所の(Y座標 div 解答欄1つの高さ) + 1 が解答用紙の番号になるはず
OutPutDebugString(PChar(IntToStr((Y div 解答欄1つの高さ) + 1)));
end;
実行(F9)して、確認。
必要と思われる変数 i, j を宣言して・・・
あとは Gridコントロールへ SetFocus するコードを書くだけ!
procedure TFormCollaboration.imgAnswerMouseDown(Sender: TObject;
Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
var
i,j:integer;
begin
//imgAnswerの高さは、解答欄1つの高さ × 解答用紙数 だから
//クリックした場所の(Y座標 div 解答欄1つの高さ) + 1 が解答用紙の番号になるはず
OutPutDebugString(PChar(IntToStr((Y div 解答欄1つの高さ) + 1)));
i:= (Y div 解答欄1つの高さ) + 1;
//SetFocus
j:= StrToInt(現在選択している解答欄の番号);
StringGrid1.Col:= j;
StringGrid1.Row:= i;
StringGrid1.SetFocus;
end;
上のコードでは、わかりやすさのため変数(記号)ではなく、そのかわりに「解答欄1つの高さ」等のように説明の文字列で記述しています。また、採点ミスを防止する観点から、Gridコントロールに表示する入力可能な列は、現在選択(=画像として表示)している解答欄に対応する1列のみとしています。
これで理想としていたカタチの採点プログラムに一歩近づけたように思います。ユーザーに案内したい採点方法は、サっと見て全員が良く出来ている設問であれば、最初に全員正解として得点を一括自動入力し、誤りの解答のみ、解答欄画像を見ながらチェックしてクリック、自動選択された採点欄のセルにゼロ(得点)を入力する方法です。
3.まとめ
案ずるよりナントカといいますが、ほんとうにその通りで、内心、ずっとできるかなー? なんて思っていたことが、案外、基本的な知識だけで簡単に実現できてしまいました!
//Integer 型で、割り算をしたいときは、整数除算の演算を行う div を使う
A div B //A ÷ B の商が取得できる
あとは、やりたいことを実現するアルゴリズムを考えるだけですね!
プログラミングしていて、いちばんしあわせで、楽しい時間を過ごせました☆
【注意!】
画像の表示倍率の変更が伴う場合には、表示倍率に合わせてプログラムの変更が必要です。完璧には動作しませんが、ある程度使える(と思われる)表示倍率の変更に対応するコードは次の通りです(クリック位置が画像の下へ行くほど、誤差が大きくなります)。
procedure TFormCollaboration.imgAnswerMouseDown(Sender: TObject;
Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
var
i,j,w:integer;
k:double;
begin
//imgAnswerの高さは、解答欄1つの高さ × 解答用紙数 だから
//クリックした場所の(Y座標 div 解答欄1つの高さ) + 1 が解答用紙の番号になるはず
OutPutDebugString(PChar(IntToStr((Y div 解答欄1つの高さ) + 1)));
i:= (Y div 解答欄1つの高さ) + 1;
//表示倍率が100%の時
if Edit1.Text='100' then
begin
i:=(Y div 解答欄1つの高さ)+1; //このアルゴリズムは記録として残したい
end else begin
//表示倍率が100%ではない時
k:= 解答欄1つの高さ * (StrToFloat(Edit1.Text)/100);
i:=Ceil(Float(Y)/k); // <- とりあえずこれで使えるカモ?
end;
4.お願いとお断り
このサイトの内容を利用される場合は、自己責任でお願いします。記載した内容を利用した結果、利用者および第三者に損害が発生したとしても、このサイトの管理者は一切責任を負えません。予め、ご了承ください。