- - PR -
モードレスダイアログアクティブ時のショートカットキー
投稿者 | 投稿内容 | ||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
投稿日時: 2007-06-15 16:24
こういう動きをするとは... 想定の範囲外でした。orz
やはりキーの伝播を考えた方が良いでしょうか。私ももう少し考えたいと思います。orz _________________ C# と VB.NET の入門サイト じゃんぬねっと日誌 | ||||||||||||
|
投稿日時: 2007-06-15 16:52
お付き合い頂きありがとうございます。
少し別の現象になりますが、モードレスダイアログがアクティブになっていると、 メインフォームのメニューがワンクリックで展開されません。 つい最近こんな話題がありましたよね。 そういうこともありますので、アクティブにしない方向で処理できるのであれば そちら方がいいとは思っています。 ヒントは頂けましたので、私も自分なりに考えてみたいと思います。 | ||||||||||||
|
投稿日時: 2007-06-15 17:00
様々な方法がありますが、
KIさんの最初のやり方のように、キーをなんとかするのであれば ProcessCmdKeyを用いるのがよいでしょう。
ちなみに、 MainMenuコントロールは Form.ProcessCmdKey->MainMenu.ProcessCmdKeyの順に呼ばれ、 そこでショートカット判定を行っています。 ToolStripコントロールの場合は Control.ProcessCmdKey->ToolStripManager.ProcessCmdKeyの順に呼ばれます。 うまく望みのMenuのProcessCmdKeyを呼べばショートカットを判定してくれます。 ただ、WndProcやProcessCmdKeyなどは、 自分で作ったり、呼んだりするのはお勧めしません。 いろいろ不具合が起きる可能性があり、 その場合原因を調べたり対応策をしらべるのがとても大変です。 Microsoftのお勧めどおりに作るのが一番です。 今回も、ダイアログ側からメインフォームのショートカットが呼ばれないのは それなりにわけがあります。 ビジネスならよくよく動作確認を行うほうがいいでしょう。 ちなみに、じゃんぬさんのFormを追加してしまう方法ですが、 MDIを使うと問題を解決できます。 .Net2.0では1.1と違いMDIはある程度まともに動きます。 追記:ちょっと不親切なコードだったので修正 更に追記:修正したら間違ってたので修正。 [ メッセージ編集済み 編集者: れい 編集日時 2007-06-15 17:07 ] [ メッセージ編集済み 編集者: れい 編集日時 2007-06-15 17:54 ] | ||||||||||||
|
投稿日時: 2007-06-15 18:01
お返事ありがとうございます。
MDIを使うということは、Formを追加するのではなく、 MdiParent にメインフォームを設定して Show するという意味ですよね? 私も前の投稿に書きましたが、MDIの子ウィンドウは理想的な動きをしてくれます。 ですから、これと同じようなことを、MDIの子でないフォームでできないかと思ったのです。 説明していませんでしたが、既にMDIで作成しています。 ドキュメントを開くと、MDIの子ウィンドウを開いてそれを表示します。 今回問題になっているツールボックスのようなウィンドウは、 開いている全てのドキュメントウィンドウから使用されるものです。 このツールボックスのようなウィンドウはMDI子としてではなく、 通常のモードレスダイアログとして開いているという状態です。 そこで試しに、モードレスダイアログとして表示していたこのウィンドウも、 MDIの子に含めてみたところ、ショートカットキーも機能しましたし ダイアログ上のコントロールの動作も問題ありませんでした。 これで機能的には要件を満たすことはできそうです。 ですが、個人的にはどうも腑に落ちない部分があります。 MDI=Multiple Document Interface という意味からすると、 MDIの子ウィンドウは、ドキュメントと関連付けられたものであるべきで、 ツールボックスのようなものは、ここに含めるべきでないと思うからです。 何か、もっとスマートな方法があればと思うのですが… | ||||||||||||
|
投稿日時: 2007-06-15 19:18
すみません。よく読んでいませんでした。 このコードは、Ctrl + S とか個別のキーの判定が不要で、 システムキー入力を先に親フォームに処理させているのですね。 今はすぐ試すことができないのですが、今度試させて頂きます。 「Microsoftのお勧めどおりに作るのが一番」だとは確かに思いますけど、 その Microsoft の製品でも、ツールボックスみたいなものを持ったものがあり、 それがアクティブになっていても、ショートカットキーは有効なのですよね。 例えば Visual Studio のさまざまなウィンドウも、 ドッキングを解除してフロートにした状態であれば、 私の作ろうとしているものとそう変わらないと思うのですが、 ショートカットキーは有効です。 | ||||||||||||
|
投稿日時: 2007-06-15 19:52
MDIは親があります Control.ProcessCmdKeyで親のProcessCmdKeyを呼んでいるようですので、 ショートカットは動きます。 モードレスダイアログは親がないので、 メインフォームのProcessCmdKeyが呼ばれないので ショートカットは動きません。
どうデザインするかは人それぞれですから、 動けばどんなのもいいんでしょう。 ただ、他人にわかりやすいデザインやプログラムの楽なデザインはあります。 MSの標準的なデザインは、 過去の遺産をひきずりつつ如何にわかりやすく、コーディングしやすくするか、 それなりに考えられています。 探すのがめんどくさいので省略しますが、 どこかにMSのデザインガイドがあると思います。 モードレスダイアログがアクティブなときに 親のショートカットが呼ばれないのは ショートカットの混乱を防ぐためでしょう。 モードレスダイアログにはなにが表示されているかわかりません。 メインフォームのドキュメントの、サブ項目を表示していたとすると、 Ctrl+Sはメインフォームのドキュメント全体を保存するのか、 サブ項目のみを保存すればいいのか、わからなくなります。 それをプログラマが明示的に支持できるよう、 ProcessCmdKeyはOverridableになっていて、 デフォルトではOwnerのProcessCmdKeyを呼ばないようになっているんだと 解釈しています。 Win32のAcceleratorを使わずにProcessCmdKeyで KeyCodeをパースしているのもそのせいだと思います。 参考までに、昔まとめた私のデザインガイドです。 1 そもそもMDIを使わない方法を考える。 2 すべてのMDIに共通のツールでしたら、 普通はメインフォームのメニューやツールバーに入れる。 3 入りきらない場合、特殊なレイアウトにしたい場合で、 そのときにやる気があったら クライアント領域でない、特殊な場所にコントロールを配置する。 4 メインフォームのツールバーに入りきらない場合、 オプショナルなものなら アクティブにならないモードレスダイアログを使います。 5 テキストボックスなどが配置されていて、 アクティブにならないと困る場合は Ownerを設定したモードレスダイアログを使います。 4、5の場合、 OwnerのProcessCmdKeyを呼ぶようにコーディングします。 ProcessCmdKeyはProtectedなので、普段はFriendなラッパーを使ってます。 モードレスダイアログのタイトルバーは小さいものを使います。 アクティブにしたくないときや小さいタイトルバーを使いたいときは以下のコードを使います。
[ メッセージ編集済み 編集者: れい 編集日時 2007-06-15 20:24 ] | ||||||||||||
|
投稿日時: 2007-06-18 11:42
しばらく環境が手元になかったので、返事が遅くなりすみません。
丁寧に説明して頂きありがとうございます。 教えて頂いた ProcessCmdKey をオーバーライドする方法で、実現することができました。
言われてみれば確かにその通りだと思いました。 ですが、ProcessCmdKey は protected ですので、 これだけの機能を実現するために、ラッパーメソッドを作ったり、 いろいろとイレギュラーなコーディングをする必要があります。 こういう仕様は割と一般的と思われるだけに、 もう少し簡単な方法が用意されていてもいいのに…とは思いました。
大変参考になりました。 今回の私のケースは、やっぱり5番っぽいです。 ダイアログのレイアウトや、中のユーザーコントロールに癖がありますので、 ツールバーで実現するのは難しいです。
WS_EX_TOOLWINDOW の方は、Form.FormBorderStyle に FixedToolWindow または SizableToolWindow を指定すれば ExStyle を使わずにできるようです。 |