DOBON.NET DOBON.NETプログラミング掲示板過去ログ

"&"を使わずにボタンにショートカットを割り当てたい

環境/言語:[WinXP]
分類:[.NET]

お世話になります。
ショートカットの作成方法についての質問です。

ボタンに [Alt + N] のようなショートカットキーを割り当てることは、
ボタンのテキストに &N という具合にキーの前に "&" を入れて
可能なようですが、ボタンの名称を変更することなく
キー割り当てをする方法はあるのでしょうか?

ヘルプを見ると、MenuItem.Shortcutでいちおうそれに近いものは
あるようなので、最悪、visible=falseのメニューを作り、
それにボタンと同じ動作をするメニューを用意して、
それにキーを割り当てようかと考えています。
(できるのかどうかまだ試していませんが...)

ただ、いかにもスマートじゃないですし、できれば避けたいと
考えています。

ご指導いただけると幸いです。
■No4105に返信(Ken-koさんの記事)
> お世話になります。
> ショートカットの作成方法についての質問です。
>
> ボタンに [Alt + N] のようなショートカットキーを割り当てることは、
> ボタンのテキストに &N という具合にキーの前に "&" を入れて
> 可能なようですが、ボタンの名称を変更することなく
> キー割り当てをする方法はあるのでしょうか?
>
> ヘルプを見ると、MenuItem.Shortcutでいちおうそれに近いものは
> あるようなので、最悪、visible=falseのメニューを作り、
> それにボタンと同じ動作をするメニューを用意して、
> それにキーを割り当てようかと考えています。
> (できるのかどうかまだ試していませんが...)
>
> ただ、いかにもスマートじゃないですし、できれば避けたいと
> 考えています。
>
> ご指導いただけると幸いです。
>

KeyPressイベントを使ってみてください。
りょう様

お世話になります。
以下、ヘルプをみながらちょっとコードを書いてみました。

Private Sub MyTexBox1_KeyPress(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyPressEventArgs) Handles MyTexBox1.KeyPress
Debug.WriteLine(e.KeyChar & " _ " & Asc(e.KeyChar))
End Sub

これで、[Alt + ○]では動きませんが、[Ctrl + ○] では、とりあえず
押したキーに対して固有のアスキーコードと記号が帰ってくるようになりました。

さて。
この例ですと、MyTexBox1のイベントなので、当該テキストボックスに
フォーカスがあるときしか動作しないようなのですが、このイベントを
このテキストボックスがあるフォームがアクティブなときであれば
どのコントロールにフォーカスがあるときでも生じさせるようにするには
どうしたらよいのでしょうか?

後ろの Handles 以下にそのウィンドウにあるコントロールを列挙していけば
可能ではあると思うのですが、それですと、コントロールを
追加、削除するときの手間がややこしくなるので、避けたいと考えています。

また、[Alt + ○]というショートカットも可能であれば取り入れたいと
思っております。

そもそも、私の理解が不足しているゆえに上のコード自体がマズい、
という気もしていますが...。
もう少しご指導願えると幸いです。
フォームイベントでキャッチした方がスマートかもしれません。
以下は、私がグループ開発の際にクラスライブラリとしてコーディングしたものです。
(無数のフォームがある場合はクラスライブラリとした方が楽なもので・・・)
そのグループ開発では各画面にショートカットが定義されていますが、働きが違うので、
ショートカットキーが押されてからの処理は、関数ポインタを使用して各モジュールへ依存させてます。
関数ポインタとなっているのは、EventThrowFunction()です。
各アプリケーションの開始時の初期化でEventThrowFunctionをAddressOfで飛ばしたい関数を指定します。
単独でしか使用しないのならば、Delegateを使用せず、直接関数を呼んでください。

参考になれば、嬉しいのですが・・・

Public Class clsForm
  Private WithEvents mpForm As Form

  '(Define)デリゲード
  Public Delegate Sub DelegateThrowFunction(ByVal iFunctionKey As Integer)

  '(Define)関数ポインタ
  Public EventThrowFunction As DelegateThrowFunction

  ' クラスの初期化
  Friend Sub Initialize(ByRef pForm As Form)
    pForm.KeyPreview = True
    mpForm = pForm
  End Sub

  '「Form::KeyDown」
  Private Sub mpForm_KeyDown(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyEventArgs) Handles mpForm.KeyDown
    fbShiftPress = e.Shift

    Select Case e.KeyCode
      Case Keys.Return
        ' 次のコントロールへ遷移
        Call MoveNextFocus(mpForm, Not fbShiftPress)
      Case Keys.F1 To Keys.F12, Keys.Escape '←ココに列挙する
        ' ファンクションキーの定義関数へ
        Call EventThrowFunction(e.KeyCode)
    End Select
  End Sub

End Class
お世話になります。

申し訳ありません。お返事がだいぶ遅れてしまいました...。

Delegate, 関数ポインタともに使用した経験もどういうものなのかの知識もなく、
コードを見ていても何をしているのかさっぱり分からず、
自分でいろいろいじってみようにも、どこをどういじるべきなのか、
そもそも、どうやって自分の環境にテストとして持ってくるのかも分からず、
ずっと途方にくれておりました...。

とりあえず、フォームのほうでこのクラスを呼び出す部分についての
サンプルを見せていただけないでしょうか...。

もうちょっと易しいステップとしては、デリゲードは使用しない、というのは分かったのですが、
ポインタが何をしているものなのかも分かりません。

お手数ですが、どうかよろしくお願いいたします。
> お世話になります。
> 申し訳ありません。お返事がだいぶ遅れてしまいました...。
いえいえ。ご都合があるでしょうから、別にいいですよ。

> Delegate, 関数ポインタともに使用した経験もどういうものなのかの知識もなく、
> コードを見ていても何をしているのかさっぱり分からず、
> 自分でいろいろいじってみようにも、どこをどういじるべきなのか、
> そもそも、どうやって自分の環境にテストとして持ってくるのかも分からず、
> ずっと途方にくれておりました...。
自分でやろうとすることが大切ですよね。

> とりあえず、フォームのほうでこのクラスを呼び出す部分についての
> サンプルを見せていただけないでしょうか...。
> もうちょっと易しいステップとしては、デリゲードは使用しない、というのは分かったのですが、
> ポインタが何をしているものなのかも分かりません。
> お手数ですが、どうかよろしくお願いいたします。

デリゲード(関数ポインタ)については、今回は説明致しません。
とにかく、実装させることを優先的に考えますね。
面倒なので継承させることにします。

まず、このようなクラスを作ります。

Public Class ClassForm
Inherits System.Windows.Forms.Form  ' Formクラスを継承

' Form::KeyDown
Private Sub Form_KeyDown(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyEventArgs) Handles MyBase.KeyDown
fbShiftPress = e.Shift

Select Case e.KeyCode
Case Keys.Return
Call MoveNextFocus()  ' フォーカスを遷移させる関数
Case Keys.F1 To Keys.F12, Keys.Escape
' TODO:ここにコールする関数を書いてください。
End Select
End Sub

End Class

次に対象のフォームを以下のようにします。

Friend Class frmMain
  Inherits ClassForm  ' ↑のClassFormを継承

  〜省略〜

End Class

「Inherits ClassForm」で、↑のClassFormを継承しています。
これで、他のフォームにも使用可能です。
わからなければ、継承さえすれば「Form::KeyDownイベント」内に書かれたコードが
どのフォームでも実行されるものと考えてください。
まあ、拡張なりなんなりしてください。

TODO:ここにコールする関数を書いてください。の部分にボタンによって、
処理を分岐させる関数などを呼べばOKなのですが・・・
以前、カキコしたように複数のプロジェクトで使用するときは、
ClassFormからは、どのプロジェクトの分岐関数を呼べば良いのかわからないので、
関数ポインタ(デリゲード)が必要になる、というわけです。

関数の概念自体がわからない場合は勉強してください。
関数の概念がわかれば関数ポインタは楽勝のハズです。

このあたりでも見てみてください。
http://santamartadotnet.hp.infoseek.co.jp/documents/vbdotnet/eventanddelegate.html

何か、拙い長文になってしまって、自分で読んでもわけがわかんなくなってきました。
Ken-koさんは、どのあたりまでVB.NETの言語仕様を理解されているのでしょうか?
イベントの概念、アクセシビティ(スコープ)の概念、
インスタンス(クラス)の概念などなど、
どのあたりまで理解されているか、教えて頂かないと、説明も難しいと思われます。
よくわからない用語が出ても理解できないと思いますので・・・。
または、そんなことは知っている!!というのもあるかと思いますので・・・。
お世話になります。
ずいぶんお返事が送れてしまい、大変申し訳ありませんでした。
どうかこれからもお付き合いください。

本日、時間ができてようやく継承フォームでの実装をゆっくり試すことができました。
なのですが、とりあえずその前に...。

お見せいただいたコードで、とりあえずコントロールが無い状態では
キー操作を受け取ることができるようになりました。

なのですが、フォーム上のコントロールにフォーカスがあるときには、
このイベントハンドラは反応しませんでした。
(当たり前だ、と言われそうですが (^^; )

コントロールにフォーカスがある状態でもKeyDownイベントを受け取りたい
(というか、どこにフォーカスがあってもキー操作を受け取りたい)
と思っているのですが、どうしたらよいのでしょうか...。

引き続きご指導願えれば幸いです。
返信が送れて申し訳ありません。
最近、かなり修羅場ってるので・・・

> お見せいただいたコードで、とりあえずコントロールが無い状態では
> キー操作を受け取ることができるようになりました。
> なのですが、フォーム上のコントロールにフォーカスがあるときには、
> このイベントハンドラは反応しませんでした。
> (当たり前だ、と言われそうですが (^^; )
> コントロールにフォーカスがある状態でもKeyDownイベントを受け取りたい
> (というか、どこにフォーカスがあってもキー操作を受け取りたい)
> と思っているのですが、どうしたらよいのでしょうか...。

FormのKeyPreviewプロパティがFalseになっていませんか?
Trueにすれば受け取ることはできます・・・。(VB6と同じ)ですが、
ProcessDialogKeyをオーバーライドした方がスマートかもしれません。
ただし、ProcessDialogKeyメソッドを普通にオーバライドするだけだと、
DropDownListでないComboBoxで、2回キーが送信されるのでちょっと工夫が要ります・・・
または、ShortcutKeyプロパティ付きのカスタムコントロールを自作するとか・・・
他にも色々あるかと思います。
特にグループ開発などで使うと、デザイナからプロパティとして変更できると喜ばれます。

んー、サンプルコードをココに書くと、長くなるし・・・
かといって、不特定多数の人が見るところで、ファイルをうぷしたくないし・・・
メールアドレスを教えていただければ、サンプルをソリューションごと送りますが・・・。
Ken-ko です。お世話になります。
こちらこそ、亀レス続きで大変失礼しております。

> FormのKeyPreviewプロパティがFalseになっていませんか?
> Trueにすれば受け取ることはできます・・・。(VB6と同じ)ですが、

こちら、無事解決いたしまいた。ありがとうございます。
おかげさまで、最低限のことは [Ctrl + ○]という形で実現できるようになりました。

> メールアドレスを教えていただければ、サンプルをソリューションごと送りますが・・・。

kenko01@hotmail.com がメールアドレスになります。
そのような貴重なものまでお見せいただけるとしたら、本当に有難いです。

何からなにまで申し訳ありません。じっくり研究させていただきたいと思います。
(本来遠慮すべきところかとは存じますが...)

この度は本当にありがとうございました。
どうか今後ともよろしくお願いいたします。
解決済み!

DOBON.NET | プログラミング道 | プログラミング掲示板