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

MDI子ウィンドウの切替時のちらつきをなくしたい

環境/言語:[WinXp SP2 + VB2005 Express +.NET2.0]
分類:[.NET]

はじめまして。

VB2005にて、こちらの記事の「MDIアプリケーションを作成する」を
参考にMDI+TABのブラウザを作っています。MDI自体はうまく動作しているのですが、
下記の状態でのちらつきを解消する方法を探しています。

1.MDI子ウィンドウをいくつか作って最大化する
2.Menuで子ウィンドウを切り替える

この時に、一度通常サイズの子ウィンドウが一瞬表示されます。
この表示をなくしたくてGoogle等で探して、これかなというのは
見つかりました。サブクラスを使ってウィンドウメッセージを
とらえる必要があるらしいのですが、VC++のため、VB2005で
行う方法がわかりません。

↓ここが参考にしたところです。
http://forums.belution.com/ja/vc/000/314/99.shtml 
http://forums.belution.com/ja/vc/000/315/13.shtml

↑上記より引用
>WM_MDICREATE や WM_MDIACTIVATE 時に
>MDIClient非表示 -> デフォルト処理 -> MDIClient表示

サブクラスでWM_MDIACTIVATEを捕まえてMdiクライアントを非表示にすれば
いいというのがわかりました。

下記のプロシージャを子ウィンドに書いてWM_MDIACTIVATEメッセージを
捕まえることまではできたのですが、サブクラスでできることと
同じことができていると考えていいでしょうか?

Protected Overrides Sub WndProc(ByRef m As System.Windows.Forms.Message)
        Const WM_CHILDACTIVATE As Integer = &H22 'MDI子ウィンドウがアクティブ
        Const WM_MDICREATE As Integer = &H220 'MDI子ウィンドウを作成

        Select Case m.Msg
            Case WM_CHILDACTIVATE
                MsgBox("childActive")
            Case WM_MDICREATE
                MsgBox("mdiCreate")
        End Select

        MyBase.WndProc(m)
    End Sub

この先、メッセージを捕まえた後、MDIClientの非表示、表示というのが
さらにわかりません。
どなたかわかる方いらっしゃらないでしょうか?
よろしくお願いします。
> サブクラスでWM_MDIACTIVATEを捕まえてMdiクライアントを非表示にすれば
> いいというのがわかりました。
>
> 下記のプロシージャを子ウィンドに書いてWM_MDIACTIVATEメッセージを
> 捕まえることまではできたのですが、サブクラスでできることと
> 同じことができていると考えていいでしょうか?

ん?
リンク先には「MDIClient」をサブクラス化してと書いてありましたが。

> この先、メッセージを捕まえた後、MDIClientの非表示、表示というのが
> さらにわかりません。

MDIClientはControlクラスですのでVisibleを使えばよいと思いますが。。。
ただし特殊なクラスですのでどんな副作用があるかはわかりません。
見つけるときはMDIParent.Controlsから探すことになります。

#今気がつきましたが、Framework2.0になって
#「内部インフラストラクチャのため使用しないでください」の記述が無くなってますね。
#だからといってどうぞ使ってくださいということではないでしょうけど。
■No16354に返信(まどかさんの記事)

こんにちは。レスありがとうございます。
いろいろ試していたので返事が遅くなってしまいました。

> リンク先には「MDIClient」をサブクラス化してと書いてありましたが。
中略
> 見つけるときはMDIParent.Controlsから探すことになります。

そうですよね。そこがよくわかってませんでした。
どぼん!さんのMDIClient探すコードを使ってMDIClientは見つかったので、
サブクラス化してWM_MDIACTIVATEを捕まえることができました。
ただ、WM_MDICREATEはまだ捕まえることができません。

visibleを使って表示、非表示を切り替えると描画がおかしくなるので、APIの
ShowWindowで対処しました。

一応、ネットを探し回って作った下記のコードで切替時の描画は見えなくなった
のですが、Menuでウィンドウを切り替えたとき、MENUがMDIClientの部分まで描画されるため、
Menuが閉じるとき一部分消えるのが遅れます。
なかなかうまくいかない物ですね。

WndProcの書き方に不安がありまして、WM_MDIACTIVATEを捕まえたときの
処理で、

>MDIClient非表示 -> デフォルト処理 -> MDIClient表示
これのデフォルト処理というのがわからなくて、

Me.DefWndProc(m)

と書いたらうまくいったので、このように書いています。
これで問題ないでしょうか?
おかしいところがありましたら指摘してください。
よろしくお願いします。

Public Class MDIClientSubClass
    Inherits NativeWindow

    Private _MdiClient As MdiClient
    Private Declare Function ShowWindow Lib "user32" _
            (ByVal hwindow As Integer, ByVal cmdshow As Integer) As Integer

    Public Sub New(ByVal MDIParentForm As Form)
        _MdiClient = GetMdiClient(MDIParentForm)
        AddHandler _MdiClient.HandleDestroyed, AddressOf Me.OnHandleDestroyed
        Me.AssignHandle(_MdiClient.Handle)
    End Sub

    Private Sub OnHandleDestroyed(ByVal sender As Object, ByVal e As System.EventArgs)
        Me.ReleaseHandle()
    End Sub

    Private Function GetMdiClient( _
    ByVal f As System.Windows.Forms.Form) _
    As System.Windows.Forms.MdiClient
        Dim c As System.Windows.Forms.Control
        For Each c In f.Controls
            If TypeOf c Is System.Windows.Forms.MdiClient Then
                Return CType(c, System.Windows.Forms.MdiClient)
            End If
        Next c
        Return Nothing
    End Function

    <System.Security.Permissions.PermissionSetAttribute(System.Security.Permissions.SecurityAction.Demand)> _
    Protected Overrides Sub WndProc(ByRef m As System.Windows.Forms.Message)
                
        Const WM_MDICREATE As Integer = &H220
        Const WM_MDIACTIVATE As Integer = &H222
        Const SW_HIDE As Integer = &H0
        Const SW_SHOW As Integer = &H5
        
        Select Case m.Msg
            Case WM_MDICREATE 'これが捕まらない
                Debug.Print("WM_MDICREATE")
            Case WM_MDIACTIVATE
                ShowWindow(CInt(_MdiClient.Handle), SW_HIDE)
                Me.DefWndProc(m)
                ShowWindow(CInt(_MdiClient.Handle), SW_SHOW)
                Exit Sub
        End Select
        MyBase.WndProc(m)
    End Sub

End Class

'Form_Load時
    Dim MDIsub As MDIClientSubClass
  MDIsub = New MDIClientSubClass(Me)
> Case WM_MDICREATE 'これが捕まらない

MSDNをみると、読んで字のごとく子ウィンドウが新しく作成されたときのメッセージですね。
なので必ず発生するわけではないようです。

> ShowWindow(CInt(_MdiClient.Handle), SW_HIDE)

間違いではないですがIntPtr.ToInt32メソッドがあるのでそっちのほうがよりよいでしょう。
■No16369に返信(まどかさんの記事)

解決済みを付けるのを忘れてしまいました。

> 間違いではないですがIntPtr.ToInt32メソッドがあるのでそっちのほうがよりよいでしょう。

このように修正させていただきます。
ありがとうございました。
解決済み!

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