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

フォームのフォーカス移動

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

現在メインメニューのフォームを表示してKeyUpから
他のフォームを開くという動作をしています。
簡単にコードを書くと


Private Sub FrmMain_KeyUp(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyEventArgs) Handles MyClass.KeyUp
    Select Case e.KeyCode
      Case Keys.NumPad1, Keys.D1
        Button1_Click(sender, e)
      Case Keys.NumPad2, Keys.D2
        Button2_Day_Click(sender, e)
      Case Keys.NumPad3, Keys.D3
        Button3_Click(sender, e)
    End Select
End Sub
'メインロード
Private Sub FrmMain_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
    '自分自身のフォームを最大化
    Me.WindowState = FormWindowState.Maximized
    'フォームのKeyPreviewを切り替える
    Me.KeyPreview = True
    ’他フォームを開くが隠す
    FrmCostProcess.Show()
    FrmCostProcess.Visible = False
End Sub
’他フォーム表示
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
   FrmCostProcess.Visible = True '表示
End Sub


これで他フォームを表示させてその表示させたフォームをまた閉じる(非表示)


’他フォームの終了
Private Sub TSBt_Back_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles TSBt_Back.Click
    Me.Visible = False '非表示
    FrmMain.Focus()
End Sub

したときにメインフォームにフォーカスを返すのですが、
メインフォームでキーの下やENTERを押すと
フォームバーを右クリックしたやつが出てきます(ウィンドウを操作するやつ)
他のキー操作をしたときはKeyUp処理してくれますがキーの下やENTERだけ
KeyUpに入らずそのようになってしまいます。


やりたいことは

・メイン表示
  ↓
・キーで他フォームを表示
  ↓
・キーで開いた他フォームを非表示
  ↓
・メインにフォーカスを戻してキー操作


どなたかご教授いただけないでしょうか?よろしくお願いします。
長文失礼しました。
本題の前に。

> Private Sub FrmMain_KeyUp(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyEventArgs) Handles MyClass.KeyUp
>     Select Case e.KeyCode
>       Case Keys.NumPad1, Keys.D1
>         Button1_Click(sender, e)

気持ちはわかりますが、考え方が誤っています。
イベントには引数があり、第一引数はイベントの送り主であるオブジェクト、第二引数はイベント独自の情報とガイドされています。
第二引数はEventArgsクラスの派生クラスで渡す値が無ければEventArgs型を渡すとガイドされています。
KeyUpとClickは確かに引数の型が同一です。
しかしそれはイベントと対応するイベントハンドラとの契約です。
・KeyUpの引数はObjectとEventArgsである。
・Clickの引数はObjectとEventArgsである。
この独立した関連性の無い二つの事実しか存在しません。
つまり、KeyUpハンドラが受け取った値をClickハンドラにそのまま渡すことに意味が無く、また、してはいけないということを理解してください。
#異なるイベントを一つのハンドラで受け取るということもできますが、個人的には先の理由で推奨しません。

あと、Clickハンドラを呼び出していますが、PerformClick メソッドを調べてください。

>     ’他フォームを開くが隠す
>     FrmCostProcess.Show()
>     FrmCostProcess.Visible = False

Showは「表示する」機能です。
非表示で待機させておくという意味であれば、必要ありません。
この2行だけで
・フォームはForm型というクラスである。
・クラスインスタンスを作成することとフォームを表示することは全く関連性の無い事柄である。
ということを理解されていないと想像できます。

たぶん、暗黙のフォームインスタンス機能を使われていると思います。
http://msdn2.microsoft.com/ja-jp/library/1fsza1t2(VS.80).aspx

オブジェクト指向では、オブジェクトインスタンスがいつ作成されいつ破棄されるかというライフサイクルを意識しなければいけません。
クラスは設計図です。インスタンスは設計図から作成した実物です。
インスタンスは複数作成することができます。
つまり、扱っているインスタンスはどれなのかを常に意識することになります。

暗黙のフォームインスタンス機能はその概念を隠蔽します。
意識しなくてもよいというのは利点であるのは確かですが、
理解せずに使っていると異なるインスタンスであることに気付かず、操作しても反応が無いというブラックホール状態になってしまいます。


本題ですが、

>     FrmMain.Focus()

FrmMainは操作しようとしている「インスタンス」ですか?
あと、Activate メソッドを調べてください。
2007/12/13(Thu) 17:14:30 編集(投稿者)
2007/12/13(Thu) 17:14:24 編集(投稿者)

さっそくの回答ありがとうございます

> ・KeyUpの引数はObjectとEventArgsである。
> ・Clickの引数はObjectとEventArgsである。
> この独立した関連性の無い二つの事実しか存在しません。

 わかっていたのですがつい・・・
ご指摘ありがとうございます。


> あと、Clickハンドラを呼び出していますが、PerformClick メソッドを調べてください。

 大変参考になりました。


> たぶん、暗黙のフォームインスタンス機能を使われていると思います。

 VB6出身なもので、暗黙のインスタンスになれてしまっていて
つい使ってしまうのです。オブジェクト指向をもう少し勉強します。


>
> 本題ですが、
>
>>    FrmMain.Focus()
>
> FrmMainは操作しようとしている「インスタンス」ですか?

 そのとおりです


> あと、Activate メソッドを調べてください。
>

ちなみに他フォームをインスタンスを閉じるのではなく非表示にしているのは
他フォームは見えなくても動いていてほしいからです。
この考え方からして無理なのでしょうか・・・

メイン    ※イベント操作(ボタンなど)のみ、他フォームを表示したりする。

他フォーム  ※ループ処理(DoEventsをかませています)、呼ばれたときだけ表示されます。
> ちなみに他フォームをインスタンスを閉じるのではなく非表示にしているのは
> 他フォームは見えなくても動いていてほしいからです。
> この考え方からして無理なのでしょうか・・・

いいえ。おかしくありませんよ。

> 他フォーム  ※ループ処理(DoEventsをかませています)、呼ばれたときだけ表示されます。

通常のフォーム上でF10を押してみてください。
するとフォーカスがシステムメニューにある状態になります。
ここで↓やEnterを押すとおっしゃる動作になります。
F10やESCを押せば元に戻ります。
書かれた現象はこのことだと思います。

たぶん、DoEventsが悪さをしていると考えられます。
何のためにどんな使い方をしているかがポイントだと思います。


新規プロジェクトで次を実行してみてください。
※Form1、Form2(Button1)、KeyPreviewとMaximizedはプロパティ設定

おっしゃる現象にはなりませんでした。

Public Class Form1
Private _Form2 As Form2
Private Sub Form1_FormClosing(ByVal sender As Object, ByVal e As System.Windows.Forms.FormClosingEventArgs) Handles Me.FormClosing
If _Form2 IsNot Nothing Then
_Form2.Dispose()
End If
End Sub
Private Sub Form1_KeyDown(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyEventArgs) Handles Me.KeyDown
Select Case e.KeyCode
Case Keys.D1, Keys.D2, Keys.D3
_Form2.Show()
End Select
End Sub
Public Sub New()
' この呼び出しは、Windows フォーム デザイナで必要です。
InitializeComponent()
' InitializeComponent() 呼び出しの後で初期化を追加します。
_Form2 = New Form2(Me)
End Sub
End Class

Public Class Form2
Private _Form1 As Form1
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Me.Hide()
_Form1.Activate()
End Sub
Public Sub New(ByVal parent As Form1)
' この呼び出しは、Windows フォーム デザイナで必要です。
InitializeComponent()
' InitializeComponent() 呼び出しの後で初期化を追加します。
_Form1 = parent
End Sub
End Class
まどかサン
ありがとうございました!!

> 通常のフォーム上でF10を押してみてください。
> するとフォーカスがシステムメニューにある状態になります。
> ここで↓やEnterを押すとおっしゃる動作になります。

 コード大変参考になりました
F10でそんなことがおきるとは想像もしてなかったです。
F10に割り付けるのはやめときます。
他に”F・”キーで割り付けないほうがいいものとかはあるんでしょうか?
またF10を押してもシステムメニューを発生させない方法とかはあるのでしょうか?

これは別スレをたてたほうがよかったかな

解決済みは押しときます。ありがとうございました。
解決済み!
Windowsのガイドラインの参考。

http://www.microsoft.com/japan/msdn/accessibility/general/ATG_KeyboardShortcuts.aspx
http://www.microsoft.com/downloads/details.aspx?FamilyID=B996E1E7-A83A-4CAE-936B-2A9D94B11BC5&displaylang=en

↑はローカルのMSDNだと
「Win32とCOMの開発」−「User Interface」−「Windows User Experience」
#たぶん。。。
解決済み!

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