起動時の画像ファイルの読み込み処理

解決


Gach  URL  2003-06-24 19:08:38  No: 3849

http://fweb.midi.co.jp/~gach/tool/
現在↑のゲーム用サードパーティーツールを作成しています。
このツールはアイコンをクリックするとそのアイコンの魔法のショートカットキーのキーボードストロークを送信するソフトです。
魔法の種類が90種類でアイコンもそれと同じで90種類あります。
ユーザーがその90種類の魔法を48個のボタンに自由に登録できるようにしてあるのですが、起動時にiniから設定を読み込んでボタンにアイコンイメージを読み込む時の処理のスマートな解決方法がありません。
現在は各TImage(ボタン)ごとにcase文を90個分書いています。
これだと画像読み込みだけで4000行以上になってしまうため、もっとスマートな解決方法はないでしょうか?
ご教授お願いいたします。


Halbow  2003-06-24 23:59:17  No: 3850

Halbow です。

> 魔法の種類が90種類でアイコンもそれと同じで90種類あります。
> ユーザーがその90種類の魔法を48個のボタンに自由に登録できる
> ようにしてあるのですが、起動時にiniから設定を読み込んでボタン
> にアイコンイメージを読み込む時の処理のスマートな解決方法がありません。

魔法の種類        1 〜 90
48個のボタン    1 〜 48

と番号付けしてあるとして、後は対応づけを ini ファイルに書き込んで
置くだけでいいのでは?  うーむ、何が問題なのか理解できませんです。

TImage に番号づけをするのは名前を ImageButton1、ImageButton2 などと
しておくと、FindComponent() で見つけることができます。 

魔法の種類を番号付けして、実際のアイコンと関連づけるのは、あらかじめ
array[1..90] of string を作って初期化しておけばいいのではないでしょうか。
アイコンがリソースなら、リソース名に番号付けしておくと簡単ですね。

実行中、たとえば20番目のボタンが何の魔法なのかを知りたいときに
備えるため、アイコンをセットするときに魔法の種類の番号を Tag に
セットしておくと便利ですね。


Gach  2003-06-25 02:21:21  No: 3851

Halbowさんありがとうございます。
ええと、アイコン画像は外部からbmpを読み込むようにしています。
ボタンにはbtnU001〜btnU048まで名前を付けています。
Tagを使えば良い、というのはわかるのですが、btnU001-btnU048まで順番に同内容の処理を繰り返すやり方がわかりません。
まだ1ヶ月程度の新米ですので理解していないことだらけでご迷惑をお掛けします。


Halbow  2003-06-25 02:49:43  No: 3852

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


Gach  2003-06-25 05:50:21  No: 3853

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  URL  2003-06-25 06:59:25  No: 3854

Halbow です。

> カスタマイズ出来るようにしてほしいという要望

どうも、意味がわかりません。上のコードでは ALT+1 をゲームの
ウィンドウに送っているわけですよね。ゲームの方は、これである
魔法であることを認識しているのですよね。ゲームのほうはプログラム
できない訳ですから、このキーデータをカスタマイズする、ということ
の意味がわかりません。特定の魔法が ALT+1 キーである、ということ
は、ゲームのほうが決めているんですよね?


Gach  2003-06-25 07:49:14  No: 3855

すみません、説明不足でした。
ゲーム自体にはALT+1のようなキーは定められているわけではなく、マクロとしてユーザーが登録できるものなのです。
つまり、こちらが作成したツールに合わせてゲーム内のマクロキーを設定している、ということです。
なので、ALT+1は別にALT+2でもCTRL+1でもゲーム内でツールが送信するキーに合わせてあげれば良い、ということです。
あまり上手く説明できませんがそういう感じです。
このゲームは色々な操作(魔法詠唱だったり発言だったり)をマクロキーに割り当てることができるんです。
このツールはキー送信を固定しているため、たとえばALT+1に「Clumsy」という魔法を設定しているのですが、ゲーム内でALT+1に他のマクロを登録している方はバッティングしてしまい、仕方なく元のマクロを別のキーに設定し直さなければいけなくなってしまいます。
それを改善するためにこちらのツールのキー送信を変えることができるようにしたいのです。


Halbow  2003-06-25 08:10:25  No: 3856

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 がら押されたボタンの魔法の種類を読みとり、
対応する配列の要素を読みとって、キーイベントを送ります。


Gach  2003-06-26 02:48:24  No: 3857

ありがとうございます。
上記のコードを参考にして、少し色々やってみたいと思います。
うまくいきましたらまたご報告いたします。


Gach  2003-06-27 22:49:43  No: 3858

色々自分なりにやってみたのですが、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ファイルを作成して、そこから設定を読み込むようにしたいです。)


Gach  2003-06-28 01:59:15  No: 3859

iniファイルの件は自己解決しました。
前者の方、引き続きよろしくお願いいたします。


にしの  2003-06-28 02:03:45  No: 3860

次の点を確認してください。

・usesに、使用するユニットを追加していない
・UOCM_MainFormが、implementsより前にかかれていない
・MahoKeydataが、publicになっていない
・fCTRLが、publicになっていない

場合によっては、publicになっていないのが問題ではなく、外部から参照するすべがないのが問題ということもあります。
fCTRLは、なんとなくprivateで宣言していて、publicnに
property CTRL: boolean read fCTRL write SetCTRL;
としていなければならなそうですし。


Gach  2003-06-28 02:15:12  No: 3861

にしのさんありがとうございます。
何となく解決できそうなのですが、typeをinterface部に記述するにはどうすればよいのでしょうか?
スクリプトは5レス前のHalbowさんに書いて頂いた物を参考にして書いています。

type
TKeyData = record
  fCTRL :Boolean;
  fSHIFT:Boolean;
  fALT  :Boolean;
  dKey  :Byte;
end;

var
  MahoKeydata:array[1..48] of TKeyData;
の位置が悪いと思うのですが・・・


Gach  2003-06-28 06:43:17  No: 3862

解決しました。
UOCM_MainForm.MahoKeydata[1].fCTRL :=   chkCtrl1.Checked;
のUOCM_MainForm.が余計でした。

助言くださった方々、ありがとうございました。


※返信する前に利用規約をご確認ください。

※Google reCAPTCHA認証からCloudflare Turnstile認証へ変更しました。






  このエントリーをはてなブックマークに追加