C# と VB.NET の質問掲示板

わんくま同盟

ASP.NET、C++/CLI、Java 何でもどうぞ

C# と VB.NET の入門サイト


■88511 / )  Re[9]: 子ウインドウのフォームがWin7になる
□投稿者/ 魔界の仮面弁士 (1811回)-(2018/09/05(Wed) 00:52:11)
No88449 (ソニン さん) に返信
>>通常の SDI における「子.Show(親)」で表示させる方法ではなく、
>>あくまでも親のクライアント領域内に子を表示させる画面構成でしょうか。
> これはどういう画面構成のことをさしていますか?
> 自分としては、
> 通常の MDI における「子.Show(親)」で表示させる方法を使うつもりですので
> 異なる方法でしょうか?

親フォームが「Owner プロパティ」と「MdiParent プロパティ」の
いずれで管理されているのか、ということです。

たとえば、
 MDIParentForm.Show()
 MDIChildForm.MdiParent = MDIParentForm
 MDIChildForm.Show(MDIParentForm)
のような記述はエラーになりますよね。

※ MDIParentForm.Show(他フォーム) は OK




>> 検索して調べたところ、恐らくこの方法を使えばいけると思います。
>> https://detail.chiebukuro.yahoo.co.jp/qa/question_detail/q1475227379
> 翻訳サイトを使ってVBに変換したのですが

意訳してみました。
MDI 親フォームに「MdiClientScrollBars プロパティ」を実装しています。


Option Strict On
Option Explicit On
Imports System.ComponentModel
Imports System.Runtime.InteropServices

Partial Public NotInheritable Class MDIParent1
    Inherits System.Windows.Forms.Form

#Region "MdiClientScrollBars プロパティ / IsMdiContainer が True の時に、MdiClient にスクロールバーが表示されるかどうかを示す値を取得または設定します"
    ''' <summary>
    ''' <see cref="IsMdiContainer"/>が<code>True</code>の時に、<see cref="MdiClient"/>にスクロールバーが表示されるかどうかを示す値を取得または設定します
    ''' </summary>
    <DefaultValue(False)>
    Public Property MdiClientScrollBars As Boolean
        Get
            Return IsMdiContainer AndAlso _MdiClientScrollBars
        End Get
        Set(value As Boolean)
            _MdiClientScrollBars = MdiClientProcWithoutScrollbars(value)
        End Set
    End Property
    Private _MdiClientScrollBars As Boolean = False
#End Region


#Region "API 宣言"
    Private Const GWL_WNDPROC As Integer = -4
    Private Delegate Function WndProcDelegate(hWnd As IntPtr, ByVal uMsg As UInteger, ByVal wParam As IntPtr, ByVal lParam As IntPtr) As IntPtr
    Private Declare Auto Function SetWindowLongPtr32 Lib "user32" Alias "SetWindowLong" (hWnd As HandleRef, nIndex As Integer, dwNewLong As IntPtr) As IntPtr
    Private Declare Auto Function SetWindowLongPtr64 Lib "user32" Alias "SetWindowLongPtr" (hWnd As HandleRef, nIndex As Integer, dwNewLong As IntPtr) As IntPtr
    Private Declare Auto Function CallWindowProc Lib "user32" (lpPrevWndFunc As IntPtr, hWnd As IntPtr, Msg As UInteger, wParam As IntPtr, lParam As IntPtr) As IntPtr
    Private Shared ReadOnly SetWindowLongPtr As Func(Of HandleRef, Integer, IntPtr, IntPtr)
    Shared Sub New()
        If IntPtr.Size = 8 Then
            SetWindowLongPtr = AddressOf SetWindowLongPtr64
        Else
            SetWindowLongPtr = AddressOf SetWindowLongPtr32
        End If
    End Sub
#End Region

#Region "MdiClient の取得処理"
    'MdiClient を保持する変数。OnControlAdded / OnControlRemoved で更新される。
    Private MdiClientHandle As HandleRef = New HandleRef(Nothing, IntPtr.Zero)

    '本来のプロシージャ
    Private MdiClientOriginalProc As IntPtr = IntPtr.Zero

    'CallbackOnCollectedDelegate 対策のため、GC されないよう保持しておく
    Private MdiClientProc As WndProcDelegate = Nothing

    Protected Overrides Sub OnControlAdded(e As ControlEventArgs)
        MyBase.OnControlAdded(e)
        If TypeOf e.Control Is MdiClient Then
            MdiClientHandle = New HandleRef(e.Control, e.Control.Handle)
        End If
    End Sub
    Protected Overrides Sub OnControlRemoved(e As ControlEventArgs)
        If TypeOf e.Control Is MdiClient Then
            If MdiClientOriginalProc <> IntPtr.Zero Then
                'MdiClient が削除される前にサブクラス化を解除しておく
                SetWindowLongPtr(MdiClientHandle, GWL_WNDPROC, MdiClientOriginalProc)
                MdiClientOriginalProc = IntPtr.Zero
            End If
            MdiClientHandle = New HandleRef(Nothing, IntPtr.Zero)
        End If
        MyBase.OnControlRemoved(e)
    End Sub
#End Region

#Region "MDI のスクロールバー制御"
    Private Function MdiClientProcWithoutScrollbars(visible As Boolean) As Boolean
        If Not IsMdiContainer OrElse MdiClientHandle.Handle = IntPtr.Zero Then
            Return False
        End If
        Dim mc = TryCast(MdiClientHandle.Wrapper, MdiClient)
        If mc Is Nothing Then
            Return False
        End If
        If visible Then
            If MdiClientOriginalProc <> IntPtr.Zero Then
                'サブクラス化解除
                SetWindowLongPtr(MdiClientHandle, GWL_WNDPROC, MdiClientOriginalProc)
                MdiClientOriginalProc = IntPtr.Zero
            End If
        Else
            If MdiClientOriginalProc = IntPtr.Zero Then
                'サブクラス化
                MdiClientProc = New WndProcDelegate(AddressOf MdiClientProcWithoutScorollbars)
                MdiClientOriginalProc = SetWindowLongPtr(MdiClientHandle, GWL_WNDPROC, Marshal.GetFunctionPointerForDelegate(MdiClientProc))
            End If
        End If
        'リサイズすることで、スクロールバーを強制再描画させる
        '(ただし mc.Dock は Fill なので、実際にはリサイズされない)
        mc.Width -= 1
        Return visible
    End Function

    Private Function MdiClientProcWithoutScorollbars(hWnd As IntPtr, uMsg As UInteger, wParam As IntPtr, lParam As IntPtr) As IntPtr
        'サブクラス化して WM_NCCALCSIZE を無視する
        Const WM_NCCALCSIZE As UInteger = 131UI
        Return If(uMsg = WM_NCCALCSIZE, IntPtr.Zero, CallWindowProc(MdiClientOriginalProc, hWnd, uMsg, wParam, lParam))
    End Function

    Protected Overrides Sub OnLoad(e As EventArgs)
        MyBase.OnLoad(e)
        'MdiClient のスクロールバーの状態を更新する
        _MdiClientScrollBars = MdiClientProcWithoutScrollbars(IsMdiContainer AndAlso _MdiClientScrollBars)
    End Sub
#End Region

End Class

返信 編集キー/


管理者用

- Child Tree -