http://fweb.midi.co.jp/~gach/tool/
現在↑のゲーム用サードパーティーツールを作成しています。
このツールはアイコンをクリックするとそのアイコンの魔法のショートカットキーのキーボードストロークを送信するソフトです。
魔法の種類が90種類でアイコンもそれと同じで90種類あります。
ユーザーがその90種類の魔法を48個のボタンに自由に登録できるようにしてあるのですが、起動時にiniから設定を読み込んでボタンにアイコンイメージを読み込む時の処理のスマートな解決方法がありません。
現在は各TImage(ボタン)ごとにcase文を90個分書いています。
これだと画像読み込みだけで4000行以上になってしまうため、もっとスマートな解決方法はないでしょうか?
ご教授お願いいたします。
Halbow です。
> 魔法の種類が90種類でアイコンもそれと同じで90種類あります。
> ユーザーがその90種類の魔法を48個のボタンに自由に登録できる
> ようにしてあるのですが、起動時にiniから設定を読み込んでボタン
> にアイコンイメージを読み込む時の処理のスマートな解決方法がありません。
魔法の種類 1 〜 90
48個のボタン 1 〜 48
と番号付けしてあるとして、後は対応づけを ini ファイルに書き込んで
置くだけでいいのでは? うーむ、何が問題なのか理解できませんです。
TImage に番号づけをするのは名前を ImageButton1、ImageButton2 などと
しておくと、FindComponent() で見つけることができます。
魔法の種類を番号付けして、実際のアイコンと関連づけるのは、あらかじめ
array[1..90] of string を作って初期化しておけばいいのではないでしょうか。
アイコンがリソースなら、リソース名に番号付けしておくと簡単ですね。
実行中、たとえば20番目のボタンが何の魔法なのかを知りたいときに
備えるため、アイコンをセットするときに魔法の種類の番号を Tag に
セットしておくと便利ですね。
Halbowさんありがとうございます。
ええと、アイコン画像は外部からbmpを読み込むようにしています。
ボタンにはbtnU001〜btnU048まで名前を付けています。
Tagを使えば良い、というのはわかるのですが、btnU001-btnU048まで順番に同内容の処理を繰り返すやり方がわかりません。
まだ1ヶ月程度の新米ですので理解していないことだらけでご迷惑をお掛けします。
Halbow です。
> btnU001-btnU048まで順番に同内容の処理を繰り返すやり方がわかりません。
簡単な例をやってみましょう。
新規で Form1 に TImage を三つ配置し、btnU001、btnU002、btnU003 と
名前をつけてください。そして、Label1 を一つ置いてください。
つぎに、[shift] キーを押しながら、三つの TImage をクリックして選択
し、その状態でオブジェクトインスペクタのイベントの OnClick のところを
ダブルクリックして空のイベントハンドラをつくります。あと、Form1 の
OnCreate を以下のようにします。
type
TForm1 = class(TForm)
BtnU001: TImage;
btnU002: TImage;
btnU003: TImage;
Label1: TLabel;
procedure FormCreate(Sender: TObject);
procedure BtnU001Click(Sender: TObject);
private
{ Private 宣言 }
public
{ Public 宣言 }
end;
var
Form1: TForm1;
implementation
{$R *.DFM}
procedure TForm1.FormCreate(Sender: TObject);
var
i:integer;
IM:TImage;
begin
Randomize;
for i := 1 to 3 do begin
IM := TImage(FindComponent('btnU'+Format('%.3d',[i])));
if Assigned(IM) then begin
IM.Tag := i;
with IM.Canvas do begin
Brush.Color := Random($FFFFFF);
FillRect(IM.ClientRect);
end;
end;
end;
end;
procedure TForm1.BtnU001Click(Sender: TObject);
begin
Label1.Caption := 'btnU'+Format('%.3d',[TImage(Sender).Tag])+
'がクリックされました';
end;
実行すると、三つの TImage が適当な色で塗りつぶされ、それのどれか
をクリックすると、そのことが Label1 に表示されます。
あと、90種類のビットマップをリソースとしてexeやdllに取り込んでおくと
便利につかえますよ。番号つきのリソース名でアクセスできますし。
方法は以下のHPに書いてあります。
http://halbow.cool.ne.jp/Notes/N008.html
Halbowさん、とても丁寧な回答ありがとうございました。
無事解決いたしました。
'btnU'+Format('%.3d',[i]) というのは調べても全然それらしきものが見あたりませんでした。
非常に勉強になりました。
あと、もう一つ質問があるので引き続きここで質問させて頂きます。
キーボードストロークの送信部を以下のようにしています。
procedure TUOCM_MainForm.clickM001;
begin
hUltima := FindWindow('Ultima Online', nil); //UOのハンドルを取得
hUltima3D := FindWindow('Ultima Online Third Dawn', nil); //UO3Dのハンドルを取得
if hUltima or hUltima3D <> 0 then
begin
if hUltima <> 0 then SetForeGroundWindow(hUltima);
if hUltima3D <> 0 then SetForeGroundWindow(hUltima3D);
keybd_event(VK_MENU, 0, 0, 0);
keybd_event(Byte('1'), 0, 0, 0);
keybd_event(Byte('1'), 0, KEYEVENTF_KEYUP, 0);
keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
end;
end;
ユーザーの方から、このキーを好きな物にカスタマイズ出来るようにしてほしいという要望がたくさんあり、どう処理すればよいのか分からず途方に暮れています。
設定できるキーは CTRL,SHIFT,ALT,F1-F12,A-Z に限定して、CTRL,SHIFT,ALTの3種は使用・未使用をチェックボックスで設定し、その他のキーをコンボボックスから選ぶようにし、それをiniに保存するようにしようと思っています。
そこまではなんとか分かるのですが、それを実際に設定を読み込んでキー送信するまでの処理がどうすればいいのか全く見当も付きません。
何か良い方法はありませんでしょうか?
よろしくお願いいたします。
Halbow です。
> カスタマイズ出来るようにしてほしいという要望
どうも、意味がわかりません。上のコードでは ALT+1 をゲームの
ウィンドウに送っているわけですよね。ゲームの方は、これである
魔法であることを認識しているのですよね。ゲームのほうはプログラム
できない訳ですから、このキーデータをカスタマイズする、ということ
の意味がわかりません。特定の魔法が ALT+1 キーである、ということ
は、ゲームのほうが決めているんですよね?
すみません、説明不足でした。
ゲーム自体にはALT+1のようなキーは定められているわけではなく、マクロとしてユーザーが登録できるものなのです。
つまり、こちらが作成したツールに合わせてゲーム内のマクロキーを設定している、ということです。
なので、ALT+1は別にALT+2でもCTRL+1でもゲーム内でツールが送信するキーに合わせてあげれば良い、ということです。
あまり上手く説明できませんがそういう感じです。
このゲームは色々な操作(魔法詠唱だったり発言だったり)をマクロキーに割り当てることができるんです。
このツールはキー送信を固定しているため、たとえばALT+1に「Clumsy」という魔法を設定しているのですが、ゲーム内でALT+1に他のマクロを登録している方はバッティングしてしまい、仕方なく元のマクロを別のキーに設定し直さなければいけなくなってしまいます。
それを改善するためにこちらのツールのキー送信を変えることができるようにしたいのです。
Halbow です。
まだよく分かりませんが、以下のようにしたらどうでしょうか。
implementation
{$R *.DFM}
type
TKeyData = record
fCTRL :Boolean;
fSHIFT:Boolean;
fALT :Boolean;
dKey :Byte;
end;
var
MahoKeydata:array[1..48] of TKeyData;
procedure TForm1.FormCreate(Sender: TObject);
var
i:integer;
begin
//初期化
for i := 1 to 48 do
with MahoKeydata[i] do begin
fCTRL := false;
fSHIFT:= false;
fALT := false;
dKey := 0;
end;
// ここで ini ファイルから読みとってセットする
end;
のようにレコード型を新たに定義し、その配列を作ります。
クリックされたら
procedure TForm1.btnU001Click(Sender: TObject);
var
MahoNo:integer;
begin
hUltima := FindWindow('Ultima Online', nil); //UOのハンドルを取得
hUltima3D := FindWindow('Ultima Online Third Dawn', nil); //UO3Dのハンドルを取得
if hUltima or hUltima3D <> 0 then
begin
if hUltima <> 0 then SetForeGroundWindow(hUltima);
if hUltima3D <> 0 then SetForeGroundWindow(hUltima3D);
MahoNo := TImage(Sender).Tag;
with MahoKeydata[MahoNo] do begin
if fCTRL then keybd_event(VK_CONTROL, 0, 0, 0);
if fSHIFT then keybd_event(VK_SHIFT, 0, 0, 0);
if fALT then keybd_event(VK_MENU, 0, 0, 0);
keybd_event(dkey, 0, 0, 0);
keybd_event(dKey, 0, KEYEVENTF_KEYUP, 0);
if fALT then keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
if fSHIFT then keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
if fCTRL then keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
end;
end;
end;
のように、Sender の Tag がら押されたボタンの魔法の種類を読みとり、
対応する配列の要素を読みとって、キーイベントを送ります。
ありがとうございます。
上記のコードを参考にして、少し色々やってみたいと思います。
うまくいきましたらまたご報告いたします。
色々自分なりにやってみたのですが、MahoKeydata[i]を別ユニットで使う方法が分かりません。
UOCM_MainForm.MahoKeydata[1].fCTRL := chkCtrl1.Checked;
UOCM_MainForm.MahoKeydata[1].fSHIFT := chkShift1.Checked;
UOCM_MainForm.MahoKeydata[1].fALT := chkAlt1.Checked;
UOCM_MainForm.MahoKeydata[1].dKey := boxKey1.ItemIndex;
のようにしてみたのですが、未定義とエラーが出てしまいます。
あと、初回起動時(iniが存在しない時)に定内容のiniファイルを作成するようにするにはどうすればよいのでしょうか?
(初回起動時にあらかじめ設定の書かれたiniファイルを作成して、そこから設定を読み込むようにしたいです。)
iniファイルの件は自己解決しました。
前者の方、引き続きよろしくお願いいたします。
次の点を確認してください。
・usesに、使用するユニットを追加していない
・UOCM_MainFormが、implementsより前にかかれていない
・MahoKeydataが、publicになっていない
・fCTRLが、publicになっていない
場合によっては、publicになっていないのが問題ではなく、外部から参照するすべがないのが問題ということもあります。
fCTRLは、なんとなくprivateで宣言していて、publicnに
property CTRL: boolean read fCTRL write SetCTRL;
としていなければならなそうですし。
にしのさんありがとうございます。
何となく解決できそうなのですが、typeをinterface部に記述するにはどうすればよいのでしょうか?
スクリプトは5レス前のHalbowさんに書いて頂いた物を参考にして書いています。
type
TKeyData = record
fCTRL :Boolean;
fSHIFT:Boolean;
fALT :Boolean;
dKey :Byte;
end;
var
MahoKeydata:array[1..48] of TKeyData;
の位置が悪いと思うのですが・・・
解決しました。
UOCM_MainForm.MahoKeydata[1].fCTRL := chkCtrl1.Checked;
のUOCM_MainForm.が余計でした。
助言くださった方々、ありがとうございました。
ツイート | ![]() |