- ベストアンサー
エクセルVBA セルの入力後「Delete」キーを押したか判断するプログラム
セルに入力したあとその入力したキーが「Delete」キーかどうか判定するプログラムを作りたいのですが、下記のようにコードを書きました。 '標準モジュール Declare Function GetAsyncKeyState Lib "User32.dll" (ByVal vKey As Long) As Long 'Microsoft Excel Objects(ワークシート) Private Sub Worksheet_Change(ByVal Target As Range) If GetAsyncKeyState(46) <> 0 Then 'キーボードの「Delete」キーかどうか判定 ○○ Else ○○ End If End Sub ところが、「Delete」キーを押してもGetAsyncKeyState(46)の値が「0」になり、「Delete」キーを押してないことになってしまいます。どのようにすればよいのでしょうか? 回答よろしくお願いします。
- みんなの回答 (6)
- 専門家の回答
質問者が選んだベストアンサー
#1 のコードを部分訂正。。。。 どうも、こうやらないとダメみたい。 ' // DELキーを送信 Call Auto_Close AppActivate Application.Caption SendKeys "{DEL}", True Call Auto_Open
その他の回答 (5)
- Wendy02
- ベストアンサー率57% (3570/6232)
こんにちは。 何か、求めている方向が違っているような気がします。実際、API関数を使う場面というのは、VBAでは、ほとんど出てこないというか、私などは、VBAでは、あまり必要とすることがありません。 今回の「お礼」側に書かれて内容からすると、ある程度、既出の問題のような気がします。 全体的なマクロコードは見せられていないので、はっきりとしたことはいえないのですが、単に、このようなことではないでしょうか?入力後の移動自体というのも、関係ないような気がします。 '同じ列の違う行に自動的に入力する Private Sub Worksheet_Change(ByVal Target As Range) If Target.Count > 1 Then Exit Sub Application.EnableEvents = False Target.Offset(10).Value = Target.Value Application.EnableEvents = True End Sub
お礼
ありがとうございました。
- Wendy02
- ベストアンサー率57% (3570/6232)
こんにちは。 日にちが経ったもので、補足側に書かれると、どうしても、確認が遅くなってしまいます。多少でもよいので、お礼側に、「質問があります」とか、少しでも書かないと、補足側に付けられては、ここを再び開けるまで確認できないのです。 >ステップインするとやはり値が0になってしまいます。 どうして、同じような質問になるのか、私には良く分からないのです。 アットタイムで、その判定を取りたいなら、MsgBox を出せばよいのではありませんか? ステップモードで必ずしも正しく取れるものではありません。話が、ごちゃごちゃになっていると思うのです。VBEditor で動かして、それで、キーボードとして判定するのは、無理です。それは、VBAの範囲ではありません。あくまでも、キーボードが押され、API関数が感知する範囲だと思います。 >プログラムを一時停止して動かしたとき もともと、それは、何をするものですか?キーボード自体の判定を目的にするなら、VBAプログラムは、もうあきらめたほうがよいのではありませんか? VBAで、コードを作る場合は、Office アプリケーションの扱える範囲内で、どういう仕事を目的にするか、ということだと思います。 はたして、本当に、API関数が必要なのか、もう一度、考え直したほうがよいのではないか、と思います。Delete 自体を押したことを判定するなら、#1 さんの示した、OnKey で十分なのです。
お礼
すいません。補足に付けると確認ができないんですね。 ステップモードで必ずしも正しく取れるものではないというのは初めて知りました。 もともと、それは、何をするものですか?>これはワークシートのある一定のセルに入力したときに、同じ列の違う行に自動的に入力するようなプログラムを作りたかったからです。今セルがどこにあるのか判定するためなのですが、セルに入力すると移動し、「Del」キーの場合は移動せずに変わってしまうのでその判定をしたかったのです。 あと、オプションの入力後の移動を変えても正しく判定するようにしたいと思っていました。 ありがとうございました。
直接の回答ではありませんが、 何をしたいために「Del」キーの押下をチェックするのか判りませんが、 もし、改変されたくないセルを保護するためだけなら、「シート保護」で対応するなど、 「はたして、VBAで対応すべき」かどうかを全体的に考え直すことも必要です。 VBAを組み込んでしまうと、 1.メンテを作成者にしか頼めなくなる 2.VBAでなくても実現できることもVBAに走るクセがつく 2.マクロ入りのエクセルを開くと表示される「ウイルス」云々の警告メッセージに エンドユーザーが過剰反応してしまう。 ということがおきがちです。
お礼
そうですね。プログラムでやらなければいけないか考えなくてはいけませんね。プログラムで便利な部分と不便な部分と考えて作りたいと思います。 ありがとうございました。
- Wendy02
- ベストアンサー率57% (3570/6232)
こんにちは。 こちらで、そのコードを試してみましたが、一応、問題なく動作します。 >「Delete」キーを押してもGetAsyncKeyState(46)の値が「0」になり この部分で、どのようにチェックされているのかは分かりませんが、それは、このAPI関数取得のタイムラグの許容範囲を越えているのではありませんか?それと、念のために、GetAsyncKeyState の値をクリアしてから、やってみたらいかがでしょうか? しかし、 >セルに入力したあとその入力したキーが「Delete」キーかどうか判定するプログラムを作りたいのですが、 この内容にもよると思います。これで次のイベントが発生したら、すべてご破算になってしまいます。元が、Worksheet_Change イベントですから、他のコントロールのKeyDown やKeyUp イベントのように、キーに対するイベントにはなっていません。 #1 さんのような、OnKey で、[Delete]キーを固定した方法が良いかもしれません。Worksheet_Change イベントの場合は、[Delete]キー自体を監視するというよりも、ワークシートのデータに関わる監視のはずです。そのキー自体を監視する目的ではないでしょう。 今回、一応、以下のように試してみました。 'シートモジュール Private Declare Function GetAsyncKeyState Lib "User32.dll" (ByVal vKey As Long) As Long Private Const VK_DELETE As Long = &H2E Private Sub Worksheet_Change(ByVal Target As Range) Call GetAsyncKeyState(0&) If GetAsyncKeyState(VK_DELETE) <> 0 Then 'キーボードの「Delete」キーかどうか判定 Beep Else '------------ End If End Sub 参考: プラットフォーム SDK GetAsyncKeyState http://msdn.microsoft.com/library/ja/default.asp?url=/library/ja/jpwinui/html/_win32_getasynckeystate.asp
お礼
今更ですが、お礼の記載が大変遅くなり、申し訳ありません。 ありがとうございました。
補足
ブレークポイントを解除してプログラムを走らせたところGetAsyncKeyStateで問題なく動きました。 しかし、ブレークポイントを設定(If GetAsyncKeyState(46) <> 0 Thenの部分)してチェックしてステップインするとやはり値が0になってしまいます。 これはプログラムを一時停止して動かしたときに他の入力をしたことにより「Del」キーが無効になったということでしょうか? よろしくお願いします。
- KenKen_SP
- ベストアンサー率62% (785/1258)
ご提示していただいた方法では、 DEL キー押下 --> セルのデータが消去される --> イベント発生 となって初めてキー状態のチェックですからね、、、通常 DEL キー は長押ししないし、連打もしないですからキーの入力判定の段階では 既に DEL キーは押されてないからでは? ループで監視でもしない限り GetAsyncKeyState API での判定は無理 だと思います。 代わりに OnKey メソッドを使ってみたら? ' // 場所:標準モジュール Sub Auto_Open() Application.OnKey "{DEL}", "PressDelKey" End Sub Sub Auto_Close() Application.OnKey "{DEL}" End Sub Private Sub PressDelKey() If UCase$(TypeName(Selection)) = "RANGE" Then If ActiveSheet Is ThisWorkbook.Worksheets("Sheet1") Then MsgBox "Sheet1 で Delキーが押されました", vbInformation End If End If ' // DELキーを送信 AppActivate Application.Caption SendKeys "{DEL}", True End Sub
お礼
今更ですが、お礼の記載が大変遅くなり、申し訳ありません。 ありがとうございました。
お礼
「Onkey」でも動きますね。しかし、初心者なものでコードの内容は全部は分かりませんでした。勉強したいと思います。 ありがとうございました。