• ベストアンサー

エクセルVBA フォーム上でOnkeyがうまく出来ない

エクセルVBAでプログラムをしています。 Application.Onkeyでショートカットを指定したいのですがフォーム上ではうまく指定できません。 フォーム上での指定は不可能なんでしょうか? ショートカットを認識するケース 標準モジュールに Sub test2() MsgBox "test2" End Sub Sub Auto_Open() Application.OnKey "{b}", "test2" End Sub としてシート上で「b」を押した場合はうまくいきます。 ショートカットを認識しないケース 標準モジュールに Sub test() MsgBox "test" End Sub UserForm1フォームに Private Sub UserForm_Initialize() Application.OnKey "{a}", "test" End Sub としてフォームをロード(表示)して「a」を押しても何もおきません。 またフォームが表示されている状態で「b」を押しても何もおきません。 上記のコードはテストで作ったものなのでこれ以外はフォームを開く文以外何も書いておりませんので他との兼ね合いではないと思います。 どうすれば思ったとおりの動作になるのでしょうか? そもそもOnkeyはユーザフォームがアクティブのときは動かないのでしょうか? 動かない場合、フォームがアクティブなときのみフォームごとに違う関数を呼ぶショートカットを作る方法はありませんでしょうか? (コントロールごとにkey_downイベントで確認する方法はコントロールの数が各100個ほどあるのと、フォームが10個以上あるため出来ればやりたくありません。) 環境はwinXP、excel2003です。 よろしくお願いいたします。

質問者が選んだベストアンサー

  • ベストアンサー
  • KenKen_SP
  • ベストアンサー率62% (785/1258)
回答No.7

こんにちは。 > keypressまたはkeydownイベントを使用するしか方法はないのでしょうか。 基本的にはそのとおりです。 > 1000回書くのはナンセンスだと思い何か言い方法が無いか探している状況です。 VB とか Access のように Userform に KeyPreview プロパティーがあれば 話は簡単なのですが、残念ながら Excel にはありません。   # 何故 Access にあって、Excel には KeyPreview がないん   # でしょうね。。^^; 解決法としては、クラスモジュールを使うことになります。下記参考 URL に記事があります。一度クラスを書いてしまえば、コントロール数が増え ても減ってもコードの修正は非常に容易です。   Visual Basic 中学校   http://homepage1.nifty.com/rucio/main/main.htm   第30回 同じコードを2度書くな   http://homepage1.nifty.com/rucio/main/shokyu/jugyou30.htm その他の方法としては、   ・SetWindowsHookEx api でキーボードフックする   ・RegisterHotKey api でホットキーを設定する などでも実現可能ですが、難易度は高めです。

その他の回答 (6)

  • lark_0925
  • ベストアンサー率63% (37/58)
回答No.6

本格的にするなら、クラス化して、イベントまで作らなければなりませんが、今回のコードはそこまで詰めていません。 当該ユーザーフォームのモジュールに '=========================================================== Private Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long) Private Declare Function GetAsyncKeyState Lib _     "User32.dll" (ByVal vKey As Long) As Long Private e_l As Boolean '=========================================================== Private Sub UserForm_Activate()   e_l = False   Do Until e_l = True    Sleep 100    DoEvents    If key_code(66) Then '{b}が押された? '    実際には、ここに{b}が押されたときの処理を記述する ' または、ここで別のプロシジャーを呼び出す      Range("a1").Value = Range("a1").Value & "b" '    ここではセルA1にbを繋げている      End If    Loop End Sub '=========================================================== Function key_code(key As Long) As Boolean ' keyの値は、コントロールのKeyDownイベントのKeycodeと同値  Dim inkey As Long  key_code = False  inkey = GetAsyncKeyState(key)  If inkey <> 0 Then    key_code = True    End If End Function '=========================================================== Private Sub UserForm_Terminate()   e_l = True End Sub

  • cj_mover
  • ベストアンサー率76% (292/381)
回答No.5

ああ、すみません。 #4ですが、読み落としというか、錯誤があって頓珍漢な回答(?)でした。 #3さんのご回答に私が上書きするような話はありません。 いくつか考えついたのはありますが、どれもダミーのコントロールにフォーカスを置く方法ばかりでした。 大変失礼しました。

  • cj_mover
  • ベストアンサー率76% (292/381)
回答No.4

こんにちは 詳細はよくわかりませんが、 ご要望はこういうことではないでしょうか? Private Sub UserForm_KeyPress(ByVal KeyAscii As MSForms.ReturnInteger)   If KeyAscii = 98 Then Application.Run "test2" End Sub 私自身、滅多に使わないイベントですから、詳しい訳ではありませんが、 このイベントがある以上は、 ―OnKey が優先される―ことはないだろうな、とは思います。 ※フォームはModal表示、コントロールにフォーカスを置かない状態で確認済。

mentaiko2
質問者

お礼

ご回答ありがとうございます。 keypressまたはkeydownイベントを使用するしか方法はないのでしょうか。 質問にも書きましたが本番環境には、ボタンやテキストボックスなどコントロールがざっと1000以上(システム全体で)あります。 1000回書くのはナンセンスだと思い何か言い方法が無いか探している状況です。

  • end-u
  • ベストアンサー率79% (496/625)
回答No.3

Formヘルプの[Microsoft Forms オブジェクト モデルの全体像] を見てもらったらわかるかもしれませんが、 ExcelとMicrosoft Formsは、言わば別Applicationなので、 FormがActiveになっている時はExcel.ApplicationのOnkeyメソッドは機能しません。 [Alt]キーとの組み合わせで良ければ、[Accelerator プロパティ]を調べてみてはいかがでしょう。 ダミーでもいいので、CommandButton を追加し、そのボタンに[Accelerator プロパティ]を設定します。 Me.CommandButton1.Accelerator = "A" などとコードでも設定できますが、[プロパティウィンドウ]でも可。 [Alt]キー+[設定したキー]で、その CommandButton_Click イベントが実行できます。 その CommandButton はUserFormの非表示エリアに置いて、TabStopをFalseにしておけば あまり気にならないでしょう。 その場合はクリックイベントの最後に他のコントロールにSetFocusするようにしておいたほうがいいです。

  • marbin
  • ベストアンサー率27% (636/2290)
回答No.2

#1です。 あと、ユーザーフォームにフォーカスがあると 起動しないようです。 シートにフォーカスを移してからキーを打つと 起動します。

mentaiko2
質問者

お礼

ご回答ありがとうございます。 現在作っているプログラムはユーザがシートにフォーカスを当てる瞬間がまったくありません。 フォームがアクティブなときにいつでもショートカットキーを使用するいい方法はないでしょうか? よろしくお願いいたします。

  • marbin
  • ベストアンサー率27% (636/2290)
回答No.1

全角/半角 の違いでは? 半角に切り替えたらどうなりますか?

mentaiko2
質問者

お礼

ご回答ありがとうございます。 テキストボックスなどのコントロールは一切ありませんので常に半角です。 あえて全角にして見ましたがうまくいきません。

関連するQ&A

  • Excel 2007 VBA マクロにショートカットを割り当てる

    お世話になります。 UserForm に GotoNextItem というボタンがあり、そこをクリックすると proc_GotoNextItem というマクロを実行することにして、うまくいっています。 同じ動作を、ショートカットキー Shift+Ctrl+Nでも行わせようと思い、下のように書いてみたのですが、うまくいきません。 (ウンともスンともいいません) 何かわかるでしょうか? よろしくお願いします。 Private Sub GotoNextItem_Click() proc_GotoNextItem End Sub Private Sub UserForm_Initialize() MsgBox "start" Application.OnKey "^+{n}", "proc_GotoNextItem" End Sub Private Sub UserForm_Terminate() Application.OnKey "^+{n}" End Sub Public Sub proc_GotoNextItem() MsgBox "GotoNextItem!" End Sub フォームにボタンがあるなら Acceratator でいいじゃんと言われそうですが、フォームにフォーカスがないときがあり(それでも早見表代わりに ShowModal=False で表示させておこうと思います)それでも実行したいと思ったからです。 なお、Onkey の代わりに、 Application.MacroOptions HasShortcutKey:=True, ShortcutKey:="N" などと書くと、 「表示されていないマクロは編集されていません、[ウィンドウ再表示]を表示して、ウィンドウを表示してください」 と言われます。 よろしくお願いします!

  • エクセルVBAユーザーフォームの変数の設定方法について

    すいません、エクセルVBAのユーザーフォームの変数の設定方法について質問があります。 1 ユーザーフォームを2つ用意する。 2 それぞれにComboBox1をおく。 3 立ち上げたユーザーフォームについて、UserForm_InitializeでComboBox1に"a"のAddItemを作る。 この、「立ち上げたフォームのComboBox1に"a"のAddItemを作る」 という作業を各々のユーザーフォームに記載するのではなく、標準モジュールでまとめて記載する方法で躓いています。 Public m As String Private Sub UserForm_Initialize() ’フォーム1を立ち上げた場合   m = "UserForm1"   Call Test1(m) End Sub Private Sub UserForm_Initialize() ’フォーム2を立ち上げた場合   m = "UserForm2"   Call Test1(m) End Sub ↓ 標準モジュールに記載 Sub Test1(m As String) VBA.UserForms.Add(m).ComboBox1.AddItem "a" End Sub これだとUserForm_InitializeとTest1の間で無限ループが始まってしまい、うまく進んでくれません。 ヘルプを見ましたが、Add(変数)でユーザーフォームを変数で指定できるということ以上のことは発見できず行き詰っています。  それぞれのフォームに書けばいいだけの話なのかもしれませんが、メンテを考えると出来ればまとめて記述しておきたいと考えています。 解決方法がありましたらどうぞよろしくご教示願います。

  • エクセルVBAでフォームのボタンとコントロールツールボックスのコマンドボタン

    エクセルVBAでフォームのボタンとコントロールツールボックスのコマンドボタンについて教えてください。 実はこれまでフォームしか使ったことがないのですが、フォームのボタンですと、下記のように一つのプロシージャを多数のボタンから呼び出し、呼び出したボタンにより異なった指示が出来ます。 Sub test() x = Application.Caller Select Case x Case "ボタン 1" MsgBox 1 Case "ボタン 2" MsgBox 2 Case "ボタン 3" MsgBox 3 Case "ボタン 4" MsgBox 4 End Select End Sub コントロールツールボックスは Private Sub CommandButton1_Click() MsgBox 1 End Sub Private Sub CommandButton2_Click() MsgBox 2 End Sub のようにコマンドボタンごとにひとつずつ書くしかないのでしょうか?

  • subプロシージャーは標準モジュールではなくフォームのコードを書く部分

    subプロシージャーは標準モジュールではなくフォームのコードを書く部分に書いても問題ないのでしょうか? エクセルにVBAでフォームを挿入し、 「Private Sub UserForm_Initialize()」 などのフォームのモジュールに、 Sub test() MsgBox "あああ" End Sub という標準モジュールに書くべきのsubプロシージャーを書いてもなにもエラーにならないし正常に動きます。 subプロシージャーは標準モジュールではなくフォームのコードを書く部分に書いても問題ないのでしょうか? それともエラーにならなくても標準モジュールに書いた方がいいですか?

  • VBA 標準モジュールとフォーム

    ある標準モジュール内で生成した変数の値をフォームのコマンドボタンをクリックしたら表示されるプログラムはどうやってつくるのですか? 標準モジュール sub test() dim a as integer dim b as integer dim sum as string a=5 b=1 sum=a+b End sub フォームのコマンドボタンクリック Sub CommandButton1_Click() MsgBox sum End Sub 標準モジュールで計算した答えがフォームのコマンドボタンをクリックしたら答え6が表示されるようにしたいのですが、どうしたらできますか?

  • Excel VBA ENTERで特定のセルへ移動

    他の質問でみつけたコードですが どなたか以下のコードの内容を説明(翻訳)していただけないでしょうか よろしくお願いします。 '<標準モジュール> Private Sub ReturnDirectrion2SelectCell()  If ActiveCell.Address(0, 0) Like "A2" Then   Range("B5").Select  Else   'Original ReturnDirection の再現   On Error Resume Next   Select Case Application.MoveAfterReturnDirection   Case xlDown     ActiveCell.Offset(1).Select   Case xlToRight     ActiveCell.Offset(, 1).Select   Case xlToLeft     ActiveCell.Offset(, -1).Select   Case xlUp     ActiveCell.Offset(-1).Select   End Select  End If End Sub Sub SetKeys()   '設定用   Application.OnKey "~", "ReturnDirectrion2SelectCell"   Application.OnKey "{Enter}", "ReturnDirectrion2SelectCell" End Sub Sub SetOffKeys()  '解除用  Application.OnKey "~"  Application.OnKey "{Enter}" End Sub '----------------------------------------- 自動設定が必要な場合は、以下のコードを加えてください。 '----------------------------------------- '<標準モジュール> Sub Auto_Open()  Call SetKeys End If Sub Auto_Close()  Call SetOffKeys End If '----------------------------------------- 以上です。よろしくお願いします。

  • フォームのイベントを標準モジュールから呼び出す

    フォームのイベントを標準モジュールから呼び出す事は出来ないのでしょうか? ちなみにアクセスです。 例えば、 Private Sub Form_Load() MsgBox "test" End Sub というのはフォームを開いたときにしか発生しないですよね。 でもフォームを開いている状態でForm_Loadと全く同じ事をしてほしい時は どうすればいいですか? 標準モジュールで Sub a() Call Form_フォーム1.Form_Load End Sub としてみましたが、メソッドまたはデータ メンバが見つかりません。 (Error 461)になりました。 MsgBox "test" だけなら、 Sub a() MsgBox "test" End Sub にすりゃいいじゃん!って思われがちですが、 実際はForm_Loadイベントにはたくさんのコードが書かれています。 標準モジュールからイベントの呼び出しを教えてください。

  • エクセルマクロユーザーフォームのtxtbox値を標準モジュールに保持

    宜しくお願いします。 ユーザーフォームのtxtbox値を標準モジュールに渡してマクロを実行 るのですが、一度値をセットしたら20~30回変更が無いので標準モジュール のみショートカットで実行したいのですが値を保持してくれません。 何か良い方法は無いのでしょうか。? 'フォーム起動 Sub フォーム() UserForm1.Show End Sub +++++++++++++++++++++++++++ Private Sub CommandButton1_Click() Call モジュール '標準モジュールを呼ぶ Unload UserForm1 ++++++++++++++++++++++++++ モジュール内 Static ufX As Byte ufX = UserForm1.XXX.Text 'ufXの値を保持したい。

  • 【vba】フォームに書いてあるコードをステップインすることは不可能でしょうか?

    エクセルもアクセスも同じなんですが フォームのモジュール?に書いてあるコードを 「F8」のステップインすることは不可能でしょうか? 標準モジュールなら 「F8」で少しずつVBAコードを試すことが可能なのですが、 フォームに書いてあるほうはできません。 ひとつひとつ試したいので Private Sub コマンド1_Click() Call test End Sub とフォームのところに書き、 標準モジュールには Sub test() ・・・ End Sub と書いて 標準モジュールのほうを F8で少しずつデバッグしています。 こうするしかないのでしょうか? よろしくお願いします。

  • VBA 標準モジュールとフォーム (続き)

    先ほど、同じ質問タイトルで質問させていただいたものです。この場合どうなりますか? モジュールでの変数file_nameをフォームのボタンをクリックしたら"text.xls"が表示されるようにしたいです。 (イメージとしては、エクセルのsheet1にコマンドボタンがあってクリックするとフォームが立ち上がってフォームのコマンドボタンをクリックすると"test.xls"が表示される) モジュール Private Sub CommandButton1_Click() ←エクセルsheet1にボタンがある   dim file_name as string file_name="test.xls"   UserForm1.Show End Sub フォーム(UserForm1) Sub CommandButton1_Click() ←フォームにボタンがある MsgBox file_name End Sub

専門家に質問してみよう