Delphiで,ソフト作りに初挑戦しています。
まだローマ字もわからない我が子に,ローマ字で文字入力を
させるためのソフトです。
Formには,キーボードのボタン用にPanelを26個,StringGridに
五十音(まだ増える)の表,Editを3個をのせてあります。
procedure TForm1.StringGrid1MouseMove に
・・・・・・・・・・・・・・・・・・・・・・・
Case RC of
9: begin
Case CC of
0: begin
for i := 1 to 26 do // ここから
begin
Panels[i].color := clBtnFace;
end;
Panels[1].color := clYellow; // ここまで
Edit2.Text := 'a';
Edit3.Text := 'A';
end;
1: begin
for i := 1 to 26 do // ここから
begin
Panels[i].color := clBtnFace;
end;
Panels[2].color := clYellow; // ここまで
Edit2.Text := 'i';
Edit3.Text := 'I';
end;
「ここから」「ここまで」の部分を,1つの関数にまとめたい
のですが,どうしたらいいのでしょうか。
私は次のように自己流(VBA風)でやったら,「書き込み違反」の
エラーになりました。
procedure TForm1.IroHenko1(Pi: integer);
var
i : Integer;
begin
for i := 1 to 26 do
begin
Panels[i].color := clBtnFace;
end;
Panels[Pi].Color := clYellow;
よろしくお願いします。
多分、Panelsの数よりPiが多くなってしまったのでしょう。
HOta さん,こんにちは。
>Panelsの数よりPiが多くなってしまったのでしょう
意味がよくわかりませんが,引数の渡し方に問題があるのでしょうか。
最初の「ここから」「ここまで」の変わりに,
IroHenko1(1);
としていて,Panels[1]の色はちゃんと変わります。
引数は26以下を渡しているのですが,それでも
Panelsの数よりPiが多くなることがあるのでしょうか。
Halbow です。
> 引数は26以下を渡しているのですが,
引数をどのように算出しているか、本当にどのような場合でも 26 以下になってい
るか確認してください。関数の中に
if Pi > 26 then exit;
などと範囲チェックするといいかもしれません。
それから Pi というのは、Delphi では 円周率パイの定数にも使われている
ので違う名前の変数にしたほうが混乱がなくていいです。
Halbow です。
追伸です。
Pi がゼロの場合も考慮して
> if Pi > 26 then exit;
じゃなくて
if (Pi > 26) or (Pi<0) then exit;
のほうがいいかもしれません。
一般論ですが、RC と CC はどのように算出しているか分かりませんが
case をたくさん書く必要が出てきたときは論理の整理が出来る可能性が
ある場合があります。上のコードの場合、ひらがな全部を case 文で
判別するのはいかにも効率よくありません。RC = 9 で
CC が 0 のときは Panels[1] を黄色にし、Edit を 'a' と 'A' にする
CC が 1 のときは Panels[2] を黄色にし、Edit を 'i' と 'I' にする
..........
という論理は CC から関連づけた配列にしておくと、論理の整理ができます。
例えば
type
TRC9 = record
PanelNo:integer;
komoji:Char;
oomoji:Char;
end;
const
RC9:array[0..4] of TRC9 = ((PanelNo: 1; komoji: 'a'; oomoji: 'A'),
(PanelNo: 2; komoji: 'i'; oomoji: 'I'),
(PanelNo: 3; komoji: 'u'; oomoji: 'U'),
(PanelNo: 4; komoji: 'e'; oomoji: 'E'),
(PanelNo: 5; komoji: 'o'; oomoji: 'O'));
としておくと
0..4: begin
IroHenko1(RC9[CC].PanelNo)
Edit2.Text := RC9[CC].komoji;
Edit3.Text := RC9[CC].oomoji;
end;
というふうに一つの Case 文にまとめることが出来ます。
それから OnMouseMove イベントはものすごく頻繁に起こります。
ですから前回の RC と CC をグローバル変数などで記憶しておき
変更があったときだけ処理を実行するようにするとよいです。
すみません。訂正です。
> if (Pi > 26) or (Pi<0) then exit;
は
if (Pi > 26) or (Pi<1) then exit;
です。
Halbow さん,こんにちは。
たくさんのご指導有難うございます。
私は,エラーの原因が関数か引数かと思っていましたが,
どうやら,そうではないようです。
関数部分を全部コメントアウトして,実行しても思い通りに
動いていますが,終了のときに次のエラーが出ます。
(関数を書く前までは,正常に終了していました。)
「EAccessViolationがモジュール 〜〜.EXE のFFFFF235で発生しました。
アドレス00000235でアドレス0344315Eに対する書き込み違反が起きました」
ファイルが壊れたのでしょうか。
Halbow です。
> ファイルが壊れたのでしょうか。
さぁ、だれにも分かりませんよ。
新しくエクスプローラで、ディレクトリをつくって、そこに
*.dpr
*.dfm
*.pas
*.res
のファイルだけをコピーしてから、 *.dpr をダブルクリックして Delphi を
立ち上げ、F9 を押してコンパイル・実行しても、現象が再現するなら、
なんとんさんの書かれたコードが原因だと思います。
Halbow さん,またお世話になります。
四つのファイルをコピーして実行しました。
結果は,見事に同じエラーの発生です。
関数を書くまでは順調だったんですが,その後のコードに
問題があることがわかりました。んーっ。Delphi難しいですね。
でも,これに懲りずに再挑戦します。
それと,引数を渡して処理してもらう方法を調べたいのですが,
そのようなサイトをご存知でないでしょうか。参考書にも事例がなく,
お手上げ状態です。
ということで,ここは解決にしておきます。
HOtaさん,Halbowさん,朝早くからお付き合いくださって
有難うございました。
今後も,よろしくお願いします。
Halbow です。
> それと,引数を渡して処理してもらう方法を調べたいのですが,
> そのようなサイトをご存知でないでしょうか。
これは、あまりに一般的すぎて Tips とするには普通すぎます。
普通の文法のレベルだと思います。
seventh delphi
http://kakinotane.s7.xrea.com/
ここなんか参考になりませんか。
Halbow さん,解決マーク後も見ていただき,感謝しています。
早速下記の,アドレスで調べました。
http://kakinotane.s7.xrea.com/dirDelphi2/d053.html
引数の渡し方は,あまり変わらないなあと思いましたが,私の場合
関数名の前に TForm1.IroHenko1(P1: integer); と TForm1 を
つけないと Panels を認識してくれませんでした。
それで,あちこちのサイトの部品をつぎはぎしたコードではずかしいの
ですが,前半部分を載せます。もし,お気づきの点がありましたら,いろ
いろご指導ください。
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, Grids, ExtCtrls, StdCtrls;
type
TForm1 = class(TForm)
Pnl17: TPanel;
Pnl23: TPanel;
……………………… TPanel は合計26個
StringGrid1: TStringGrid;
Edit1: TEdit;
Edit2: TEdit;
Edit3: TEdit;
Label1: TLabel;
Label2: TLabel;
procedure FormCreate(Sender: TObject);
procedure StringGrid1MouseMove(Sender: TObject; Shift: TShiftState; X,
Y: Integer);
private
{ Private 宣言 }
// procedure IroHenko2(P1, P2: integer);
public
{ Public 宣言 }
Panels: array[1..11] of TPanel;
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.FormCreate(Sender: TObject);
var
i : integer;
begin
for i := 0 to 9 do
begin
StringGrid1.ColWidths[i] := 33;
end;
StringGrid1.Rows[0].CommaText :=
'わ,ら,や,ま,は,な,た,さ,か,あ';
StringGrid1.Rows[1].CommaText :=
',り,,み,ひ,に,ち,し,き,い';
StringGrid1.Rows[2].CommaText :=
'を,る,ゆ,む,ふ,ぬ,つ,す,く,う';
StringGrid1.Rows[3].CommaText :=
',れ,,め,へ,ね,て,せ,け,え';
StringGrid1.Rows[4].CommaText :=
'ん,ろ,よ,も,ほ,の,と,そ,こ,お';
for i := 1 to 26 do begin
Panels[i] := FindComponent('Pnl'+IntToStr(i)) as TPanel;
Panels[i].Tag := i;
end;
end;
//procedure TForm1.IroHenko2(P1, P2: integer);
//var
// i : Integer;
//begin
// if (P1 > 26) or (P1 < 1) then exit; // ここを貼りつけ
// if (P2 > 26) or (P2 < 1) then exit;
//
// for i := 1 to 26 do
// begin
// Panels[i].color := clBtnFace;
// end;
// Panels[P1].Color := clYellow;
// Panels[P2].Color := clYellow;
//end;
procedure TForm1.StringGrid1MouseMove(Sender: TObject; Shift: TShiftState;
X, Y: Integer);
var
RC, CC: integer;
begin
StringGrid1.MouseToCell(x, y, RC, CC);
if (RC = -1) or (CC = -1) then Exit;
Edit1.Text := StringGrid1.Cells[RC, CC];
Case RC of
9: begin
Case CC of
0: begin
Edit2.Text := 'a';
Edit3.Text := 'A';
end;
1: begin
Edit2.Text := 'i';
Edit3.Text := 'I';
end;
2: begin
Edit2.Text := 'u';
Edit3.Text := 'U';
end;
3: begin
Edit2.Text := 'e';
Edit3.Text := 'E';
end;
4: Begin
Edit2.Text := 'o';
Edit3.Text := 'O';
end;
end;
end;
8: begin
Case CC of
0: begin
// IroHenko2(11, 1); ←ここで関数を呼び出していました。
Edit2.Text := 'ka';
Edit3.Text := 'KA';
end;
あとは,二つのCaseの繰り返しです。すごい力技ですね。
TRC9 = record が便利そうなので,今から勉強を始めます。
以上大変長くなりましたが,私にはどこがいけないのかさっぱり
分かりません。
ご指導よろしくお願いします。
あれっ,間違えてる。
{ Public 宣言 }
Panels: array[1..11] of TPanel;
array[1..26] なのに。
早速書き換えてみます。
Halbow さん,直りました。エラーなしです。
何と単純なミス。自分でもあきれています。
とりあえず直ったので,TRC9 = record の理解と
Panels の色を順に変えていく方法(「か」の場合「K」の
ボタン文字が青に0.4秒後位に「A]が青)に取り組みます。
でも,コードで気付いたことがあったらどしどし教えてください。
よろしく。
Halbow です。
解決しそうでなによりです。
> 関数名の前に TForm1.IroHenko1(P1: integer); と TForm1 を
> つけないと Panels を認識してくれませんでした。
えーと、TForm1 クラスのメソッドにすると、そのなかではデフォルトで TForm1
クラスのフィールド変数やメソッド、TForm1 自身のプロパティーやメソッドに
アクセスできます。self の意味が分かっていれば自明です。で、一般の関数や
手続きにすると、特定のインスタンスを参照しなければなりません。上の例なら
Form1.Panels[i].Color := clBtnFace;
というふうにアクセスします。クラスや可視性などについて理解するといろいろ
と視野が広がります。
Halbow さん,何度も何度もお世話になります。
>self の意味
>クラスや可視性など
まだ全く分かっていません。でも,今回の質問で雰囲気はつかめました。
もっと勉強しなくっちゃ。
明日から,里帰りです。Halbowさんも良い年をお迎えください。
来年も,またよろしくお願いします。
ツイート | ![]() |