ホーム ] TIPS ウィンドウズ系 ] TIPS グラフィックス系 ] TIPS メルチメディア系 ] TIPS 理数系 ] TIPS 総覧 ]

上へ
W0001 時間を自動計測する
W0101 MDIメニュー
W0102 外部とのドラッグ&ドロップ

VB.NET2005 TIPS / ウィンドウズ系

W0101 MDIメニュー

最終更新:2006/11/12 内容追加

●解説

 以前のメニューではアイコンは自分で描画する必要があったが、2005では自動化された。ここでは、MDIモードにおける親と子のメニューの処理について紹介する。

 また、同じプロジェクトにあるFriend 以上の関係のオブジェクトを、New なしでインスタンスにアクセスできるようになった。少なくとも、.NET2002 では、これはできなかった。これは、MDI環境の親(のインスタンス)を、子はいつでも参照できることを意味する。従って、従来のようなやや複雑な参照環境をコードしなくて済む。

●メニュー環境

 メニューバー(MenuStrip))とツールバー(ToolStrip)がある。MDIでは、通常、子のメニューも親のバーに統合されて表示する。メニューの場合は、子のメニューのイベントは自動的のその子のインスタンスにデリゲートされるので簡単である。ツールバーの場合は、親にしかイベントは発生しないので工夫が要る。

 アイテムとして、ボタンや区切り以外に、テキストボックス、ドロップダウンリスト、ラベルなどがある。

●原理

 メニュー、ツールバー共に、アイコンはそれそれのアイテムで直接プロパティとしてパスを設定する。従来のようにイメージリストは不要。編集もエディダでも個々でもできる。また。アイテムのNameプロパティが完全になり、個々を識別できるようになった。

 ツールバーのイベントは、子にも生起されるように設定すれば、比較的楽にコードできる。


メニューとツールバー

●方法

 ツールバーの全体像を下図に示す。

●事例

 一例に過ぎないが紹介する。

○メニュー

 子のメニューは、Visible をFalse にして置く。でないと、子フォームにメニューの下地が表示される。

○アイコン

 メニューやツールに表示するアイコンは、.NET2005 で作成・編集できる。既にあるものを変更するには、エキスプローラにてアイコンを右ダウンし、コンテキストメニューで ".NET2005で編集" を選ぶと単独で編集できる。

 アイコンは 16X16 の単一サイズにし、表示方法としてはサイズ固定にすると良い。32X32が混在して、表示を自動調整にすると、大きい方のサイズ を縮小するので、エイリアスが生じる。

○子のアレンジ

 標準のウィンドウメニューにある、子フォームの並び替え(オーバーラップ、水平、垂直など、LayoutMdi(MdiLayout.Cascade)など)は、システム側で強制的に行われる。その際、アクティブになる子に対するイベントは起こらない。しかも、アレンジする前の子と異なる場合がある。このままでは、ツールバーの表示が違う子の表示になってしまう場合がある。

 以下のようにすれば良い。アレンジ後のアクティブな子を特定し、そのインスタンスの参照を獲得し、その子のメソッドを実行する。

アレンジのメニュークリックイベントにて

Private Sub mnuWindow_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles mnuWOL.Click, mnuWH.Click, mnuWV.Click
   Application.DoEvents()
   Dim mnu As ToolStripItem = sender
   Select Case mnu.Text
      Case "重ねる"
         Me.LayoutMdi(MdiLayout.Cascade)
      Case "横長"
         Me.LayoutMdi(MdiLayout.TileHorizontal)
      Case "縦長"
         Me.LayoutMdi(MdiLayout.TileVertical)
   End Select
   If Me.ActiveMdiChild IsNot Nothing Then      '子がいれば
      Select Case Me.ActiveMdiChild.Name
         Case "frmXX"
            Dim XX As frmXX = Me.ActiveMdiChild
            XX.RefreshForm()
         Case "frmYY"
            Dim YY As frmYY = Me.ActiveMdiChild
            YY.RefreshForm()
         ・・・・・・・・・・・・・・・・・・・・・・・・
      End Select
   End If

End Sub

全ての子フォームにて、以下のメソッドを追加

Friend Sub RefreshForm()
    (SetTools())                       '自分のツールの状態を正しく設定する
End Sub

 上記の方法では、子の種類が増えれば、親のコードが追加になる。それがいやなら、専用のイベントを以下のように利用する。

Event LetSetTools(sender As Object, frm As Form)


アレンジの直後
If Me.ActiveMdiChild IsNot Nothing Then      '子がいれば
    RaiseEvent LetSetTools(Me, Me.ActiveMdiChild)
End If

子においては、

Private Sub MDI_LetSetTools(ByVal sender As Object, ByVal frm As Form) Handles MDI.LetSetTools
   If Me.Equals(frm) Then       '自分であれば
    (SetTools())                       '自分のツールの状態を正しく設定する
   End If

End Sub
 

○ツールバー

 親のツールバーは特に問題なし。子のツールバーを親のツールバーに同居させる場合は以下のようにする。

・親のツールバーに子のためのツールボタンを定義する。この例では、それらのTag を 1 にする。(親の分は 0 とする)。また、親のMDIForm の名称を、MDIMain とする。この名称はFriend なので、子のインスタンスで参照可能(となった)。

・子がいない時に、子のためのボタンを見せなくする方法と、Disable にする方法がある。これは以下のようにする。 見えなくなる方が、表示がうるさくなくなると思う。

親モジュールにて

tlsMain は、ToolStrip

Private Sub MDIMain_MdiChildActivate(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.MdiChildActivate
   If Me.ActiveMdiChild Is Nothing Then                '子がいなければ子のボタンを無効にしたりする。
      For Each itm As ToolStripItem In tlsMain.Items
         If itm.Tag = 1 Then
            itm.Visible = False    'and/or
            itm.Enabled = False
         End If
      Next
   End If
End Sub

・そのときアクティブな子のボタンのみ有効にする処理は、以下のようにする。

 親のイベントを以下のようにデリゲートする。

子モジュールにて、

Dim WithEvents MDI As MDIMain = MDIMain

'MDIの型を型MDIMain にし、インスタンスMDIMain を参照設定(以前の.NET ではできなかった参照)

と参照定義しておけば、親のイベントを全て子インスタンスに取り込めるので、子がアクティブになったイベントを取り込み、以下のように処理する。

Private Sub MDI_MdiChildActivate(ByVal sender As Object, ByVal e As System.EventArgs) Handles MDI.MdiChildActivate
   Dim frm As Form = MDI.ActiveMdiChild
   If frm IsNot Nothing Andalso frm.Equals(Me) Then     'アクティブな子が自分であれば
      For Each itm As ToolStripItem In MDIMain.tlsMain.Items
        If itm.Tag = 1 Then
           Select Case itm.Name              '自分のボタンであれば
              itm.Visible = True    'and/or
              itm.Enabled = False/True       '有効/無効は子で決める
          
             case else
               itm.Visible=False                   '自分のアイテム以外は隠す
           End Select
        End If
     Next
   End If 

・ツールバーイベント処理

 同様に、親のツールバーのイベントを取り込み、以下のようにする。 この場合は、親と全ての子インスタンスの同報イベントとなるので、自分に有効なイベントを各自(親と、その時居る全ての子)識別するコードが重要となる。

子の例

Dim WithEvents ToolM As ToolStrip = MDIMain.tlsMain

Private Sub Tool_ItemClicked(ByVal sender As Object, ByVal e As System.Windows.Forms.ToolStripItemClickedEventArgs) Handles ToolM.ItemClicked
   Dim frm As Form = MDIMain.ActiveMdiChild
   Dim tls As ToolStripItem = e.ClickedItem
   If frm IsNot Nothing Andalso frm.Equals(Me) Then     'アクティブな子が自分であれば
      If tls.Tag = 1 Then
         Select Case tls.Name
           ・・・・・・・・・・・・・・・・・・・・・・・・ 自分のボタンであれば処理を行う
     メニューと対応するなら、SomeMnu.PerformClick() でOK

         End Select
      End If
   End If