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

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

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

子ウインドウのフォームがWin7になる

[トピック内 24 記事 (1 - 20 表示)]  << 0 | 1 >>

■88393 / inTopicNo.1)  子ウインドウのフォームがWin7になる
  
□投稿者/ ソニン (1回)-(2018/08/26(Sun) 19:31:09)

分類:[.NET 全般] 

Windows10、Visual Basic.NET2015の環境なのですが、
https://dobon.net/vb/dotnet/form/mdiapplication.html

このページの方法で、子フォームをもった親フォームの
プログラムを作成しました。

ところが、親フォームのスタイルはWin10のものなのですが、
子フォームのスタイルがWin7風になってしまいます。
子フォームもWin10風にしたいのですが
どのようにすれば良いでしょうか?



引用返信 編集キー/
■88396 / inTopicNo.2)  Re[1]: 子ウインドウのフォームがWin7になる
□投稿者/ とっちゃん (511回)-(2018/08/27(Mon) 11:04:34)
No88393 (ソニン さん) に返信
> Windows10、Visual Basic.NET2015の環境なのですが、
> https://dobon.net/vb/dotnet/form/mdiapplication.html
>
> このページの方法で、子フォームをもった親フォームの
> プログラムを作成しました。
>
> ところが、親フォームのスタイルはWin10のものなのですが、
> 子フォームのスタイルがWin7風になってしまいます。
> 子フォームもWin10風にしたいのですが
> どのようにすれば良いでしょうか?
>
MDIの子ウィンドウがWin7チックに表示されるのは、それはOSの制限(仕様)です。

キャプションなどの非クライアント領域の描画方法がWindows8から変わり
その関係で、MDI子フォームなどの内側のウィンドウの描画方法も変わりました。

そのため、表示が古いままになっています。

また、アプリケーションの推奨スタイルとしてもMDI形式はずいぶんと前(Vistaあたりから)から推奨されていません。

実際、WPFではMDIはサポートしていません。

引用返信 編集キー/
■88399 / inTopicNo.3)  Re[2]: 子ウインドウのフォームがWin7になる
□投稿者/ ソニン (3回)-(2018/08/27(Mon) 16:06:04)
そうでしたか・・・

MDIが推奨されていないのはなぜなのでしょうか?
複数ウインドウを使いたい場合で、
ウインドウを選択しようとして
バックグランドのウインドウやデスクトップをクリックしてしまうことがあり
非常に使いづらいので、親ウインドウが使いたいのですが
どういった理由で推奨されないのですか?

引用返信 編集キー/
■88400 / inTopicNo.4)  Re[3]: 子ウインドウのフォームがWin7になる
□投稿者/ Hongliang (678回)-(2018/08/27(Mon) 16:26:52)
https://msdn.microsoft.com/ja-jp/library/ms997581.aspx#winuifaq_topic3
とりあえず、2001年の時点でこういう記事が発表されてますね。
もちろん特定のアプリ、特定のユーザという話ならMDIの方がって意見もあるでしょうが。

// 私はAlt+Tabで選択することがほとんどなので、MDIは使いづらいですね〜。
引用返信 編集キー/
■88401 / inTopicNo.5)  Re[3]: 子ウインドウのフォームがWin7になる
□投稿者/ 魔界の仮面弁士 (1797回)-(2018/08/27(Mon) 16:31:35)
No88399 (ソニン さん) に返信
> MDIが推奨されていないのはなぜなのでしょうか?

理由のひとつとして、マルチモニタ環境と相性が悪いという点があります。
タスクバーからのアクセス製が問題視されることもありますね。

Excel なども、現在は MDI 方式を廃止していますし、
Visual Studio もタブ方式に切り替わっています。


> どういった理由で推奨されないのですか?

2001年時点の資料において、既に非推奨とされていますね。

【Microsoft Windows ユーザー エクスペリエンス FAQ】
 -「アプリケーションには SDI と MDI のどちらを使用するべきですか?」
https://msdn.microsoft.com/ja-jp/library/ms997581.aspx#winuifaq_topic3
引用返信 編集キー/
■88402 / inTopicNo.6)  Re[4]: 子ウインドウのフォームがWin7になる
□投稿者/ 魔界の仮面弁士 (1798回)-(2018/08/27(Mon) 16:55:04)
No88401 (魔界の仮面弁士) に追記
> 2001年時点の資料において、既に非推奨とされていますね。

Hongliang さんと被った。(^^;


> Excel なども、現在は MDI 方式を廃止していますし、

Excel 2013 あたりから、完全に SDI になっていますね。
https://blogs.msdn.microsoft.com/office_client_development_support_blog/2016/12/19/excel2013-changes-to-sdi/

Excel 2000〜2010 では、オプション ダイアログの[詳細設定]-[表示]あたりに
「(すべての)ウィンドウをタスクバーに表示(する)」という
オプションがありましたが、SDI 化に伴い、2013 から廃止されています。
引用返信 編集キー/
■88403 / inTopicNo.7)  Re[4]: 子ウインドウのフォームがWin7になる
□投稿者/ とっちゃん (512回)-(2018/08/27(Mon) 17:48:34)
No88399 (ソニン さん) に返信
> MDIが推奨されていないのはなぜなのでしょうか?
> 複数ウインドウを使いたい場合で、
> ウインドウを選択しようとして
> バックグランドのウインドウやデスクトップをクリックしてしまうことがあり
> 非常に使いづらいので、親ウインドウが使いたいのですが
> どういった理由で推奨されないのですか?
>
推奨の話のリンクはすでに出てるので割愛。



MDIは推奨しないというだけで、今後使えなくなるではありません。
確かにWPFやUWPアプリなど、最近のプラットフォームでは使えませんが(同じようなことをしたい場合は、自前実装)
限定的な範囲(デスクトップの WindowsForms and Win32のみ)であれば今後も利用は可能です。

あとは、見た目の問題(質問当初のもの)だけだと思って割り切って使うのか、
あれはだめだ。。。となってMDIをあきらめるのか?の2択になると思います。

結局のところUXを今まで通りとするか新しいものを取り入れるか?なので
開発コストと併せて考えればいいと思います。
引用返信 編集キー/
■88431 / inTopicNo.8)  Re[5]: 子ウインドウのフォームがWin7になる
□投稿者/ ソニン (4回)-(2018/08/29(Wed) 22:58:05)
ありがとうございます。

納得しました。

ところで、親ウインドウから子ウインドウがはみ出した場合に、
親ウインドウにスクロールバーが表れるのですが、
これを非表示するにはどうしたら良いでしょうか?

他のMDIプログラムをいくつか使っているのですが
これらではスクロールバーは表示されないので
これらと同じようにしたいのですが。

よろしくお願いいたします。

引用返信 編集キー/
■88433 / inTopicNo.9)  Re[6]: 子ウインドウのフォームがWin7になる
□投稿者/ 魔界の仮面弁士 (1803回)-(2018/08/30(Thu) 10:28:47)
No88431 (ソニン さん) に返信
> ところで、親ウインドウから子ウインドウがはみ出した場合に、
> 親ウインドウにスクロールバーが表れるのですが、
> これを非表示するにはどうしたら良いでしょうか?

通常の SDI における「子.Show(親)」で表示させる方法ではなく、
あくまでも親のクライアント領域内に子を表示させる画面構成でしょうか。


だとしたら、System.Windows.Forms.Form において、子フォームを
TopLevel = False かつ MdiParent = Nothing の状態にしておいてから
 親.Controls.Add(子)
 子.Show()
 子.BringToFront()
などとすれば、親フォームのスクロールバーの影響を受けることなく配置できます。
これで要件を満たせるでしょうか?

この場合、子.Parent が指す内容が MdiClient コントロールではなく、
親 Form そのものになります。最後に BringToFront することで、
親の MDIClient 内 よりも手前に子フォームが配置されるというわけです。


ただこれだと、そもそも親を IsMdiContainer = True にする意味が無いですし、
通常の MDI 子フォームと併用すると、聊か使い難くなるので、個人的にはお奨めしません。

そもそもスクロールバーが無いと、子フォームの右下座標が XY 共にマイナスになった場合や
子フォームの左X座標が親フォームの幅を超えていた場合に、ユーザーが子フォームへ
アクセスすることが難しくなってしまいます。
引用返信 編集キー/
■88434 / inTopicNo.10)  Re[7]: 子ウインドウのフォームがWin7になる
□投稿者/ とっちゃん (514回)-(2018/08/30(Thu) 10:51:02)
No88431 (ソニン さん) に返信
> ありがとうございます。
>
> 納得しました。
>
> ところで、親ウインドウから子ウインドウがはみ出した場合に、
> 親ウインドウにスクロールバーが表れるのですが、
> これを非表示するにはどうしたら良いでしょうか?
>
> 他のMDIプログラムをいくつか使っているのですが
> これらではスクロールバーは表示されないので
> これらと同じようにしたいのですが。
>
MDICLIENT ウィンドウの作成時に、スクロールバースタイルをつける・つけないのいずれかを選択することで
スクロールバーの有無を決めるのが本来の在り方です。

ですが、.NET にはそういう選択肢そのものがないので(問答無用でスクロールバースタイルをつける)
作成後に、あとからスタイルを外す(多分それでできると思います)かたちで対応するしかないのでは?という気がします。

このあたりが推奨されないものの操作の限界といえます。

段取りとしては、IsMdiContaioner = True を行った直後に
Controls から、MdiClient を探し、APIを使ってスタイルを外す形になります。

MdiClientの検索方法も、スタイルを設定する方法も
「MDICLIENT」
を検索キーにして検索すれば出てきます。

APIを使ってスタイルを外すコードは、C#でしたが。
引用返信 編集キー/
■88449 / inTopicNo.11)  Re[8]: 子ウインドウのフォームがWin7になる
□投稿者/ ソニン (5回)-(2018/09/01(Sat) 20:19:56)
>魔界の仮面弁士 さん


> 通常の SDI における「子.Show(親)」で表示させる方法ではなく、
> あくまでも親のクライアント領域内に子を表示させる画面構成でしょうか。

これはどういう画面構成のことをさしていますか?
自分としては、
通常の MDI における「子.Show(親)」で表示させる方法を使うつもりですので
異なる方法でしょうか?



>とっちゃん さん

検索して調べたところ、恐らくこの方法を使えばいけると思います。

https://detail.chiebukuro.yahoo.co.jp/qa/question_detail/q1475227379

翻訳サイトを使ってVBに変換したのですが

            InitializeComponent()
            Dim hwnd As IntPtr = Form1.GetWindow(Me.Handle, GW_CHILD)
                    Me.wpd = New WndProcDelegate(NewWndProc)


の三カ所でエラーが出てしまいます。


一体どのように修正すればよろしいでしょうか?


        Private Declare Function GetWindow Lib "user32.dll" (ByVal hWnd As IntPtr, ByVal uCmd As Integer) As IntPtr

        Private Declare Function GetClassName Lib "user32.dll" (ByVal hWnd As IntPtr, ByVal lpClassName As StringBuilder, ByVal nMaxCount As Integer) As Integer

        Private Declare Function SetWindowLong Lib "user32.dll" (ByVal hWnd As IntPtr, ByVal nIndex As Integer, ByVal NewWndProc As WndProcDelegate) As IntPtr

        Private Declare Function SetWindowLongPtr Lib "user32.dll" (ByVal hWnd As IntPtr, ByVal nIndex As Integer, ByVal NewWndProc As WndProcDelegate) As IntPtr

        Private Declare Function CallWindowProc Lib "user32.dll" (ByVal lpPrevWndFunc As IntPtr, ByVal hWnd As IntPtr, ByVal Msg As UInteger, ByVal wParam As Integer, ByVal lParam As Integer) As Integer

        Private Const GW_HWNDNEXT As Integer = 2

        Private Const GW_CHILD As Integer = 5

        Private Const WM_NCCALCSIZE As Integer = 131

        Private Const GWL_WNDPROC As Integer = -4

        Private PrevWndProc As IntPtr

        Public Delegate Function WndProcDelegate(ByVal hWnd As IntPtr, ByVal uMsg As UInteger, ByVal wParam As Integer, ByVal lParam As Integer) As Integer

        Private wpd As WndProcDelegate

        Public Sub New()
            MyBase.New
            InitializeComponent()
        End Sub

        Private Sub Form1_Load(ByVal sender As Object, ByVal e As EventArgs)
            Dim sb As StringBuilder = New StringBuilder(100)
            Dim hwnd As IntPtr = Form1.GetWindow(Me.Handle, GW_CHILD)

            While (hwnd <> IntPtr.Zero)
                Form1.GetClassName(hwnd, sb, sb.Capacity)
                If (sb.ToString.IndexOf("MDICLIENT") <> -1) Then
                    Me.wpd = New WndProcDelegate(NewWndProc)
                    If (IntPtr.Size = 4) Then
                        Me.PrevWndProc = Form1.SetWindowLong(hwnd, GWL_WNDPROC, Me.wpd)
                    Else
                        Me.PrevWndProc = Form1.SetWindowLongPtr(hwnd, GWL_WNDPROC, Me.wpd)
                    End If

                    Return
                End If

                hwnd = Form1.GetWindow(hwnd, GW_HWNDNEXT)

            End While

        End Sub

        Private Function NewWndProc(ByVal hWnd As IntPtr, ByVal uMsg As UInteger, ByVal wParam As Integer, ByVal lParam As Integer) As Integer
            If (uMsg = WM_NCCALCSIZE) Then
                Return 0
            End If

            Return Form1.CallWindowProc(Me.PrevWndProc, hWnd, uMsg, wParam, lParam)
        End Function
    End Class



引用返信 編集キー/
■88450 / inTopicNo.12)  Re[9]: 子ウインドウのフォームがWin7になる
□投稿者/ ソニン (6回)-(2018/09/01(Sat) 20:27:24)

Me.wpd = New WndProcDelegate(AddressOf NewWndProc)

でデバッグはできるようになりました。

しかし、

Form0.GetClassName(hwnd, sb, sb.Capacity)

のところで

追加情報:DLL 'user32.dll' の 'GetClassName' というエントリ ポイントが見つかりません。

というエラーが出て、実行することができません。

どうすれば良いですか?

引用返信 編集キー/
■88482 / inTopicNo.13)  Re[10]: 子ウインドウのフォームがWin7になる
□投稿者/ とっちゃん (515回)-(2018/09/03(Mon) 11:57:40)
No88450 (ソニン さん) に返信
> Form0.GetClassName(hwnd, sb, sb.Capacity)
>
を行っているところは、MDICLIENT のウィンドウハンドルを特定しているところですよね?

APIで探してもいいと思いますが、下記のページにある
GetMdiClient というメソッドを使うほうが簡単でいいと思います。

https://dobon.net/vb/dotnet/form/mdibackgroundimage.html

親フォームの InitializeComponent() の後(具体的には、IsMdiContainer = True がセットされた後)であれば
どのタイミングで呼び出しても取得できます。


それと、プロシージャの設定変更は、32/64 のどちらの場合でも

SetWindowLongPtr( hwnd, GWLP_WNDPROC, proc );

です。

GWLP_WNDPROC は、GWL_WNDPROC と同じ値です。
IntPtrのサイズを判定した分離処理は「不要」です。
プロシージャの変更に関しては。

引用返信 編集キー/
■88491 / inTopicNo.14)  Re[11]: 子ウインドウのフォームがWin7になる
□投稿者/ ソニン (8回)-(2018/09/03(Mon) 22:42:54)

ありがとうございます。

しかし、どのように修正したら良いか分かりません。

hwndはintptr、mcはSystem.Windows.Forms.MdiClientですが
どのように変換したら良いのですか?

また、sbはどのように取得すれば良いですか?

SetWindowLongPtr( hwnd, GWLP_WNDPROC, proc );


Me.wpdがprocに変わっていますが
procはどこで取得するのですが、
修正案を教えていただけないでしょうか?


引用返信 編集キー/
■88500 / inTopicNo.15)  Re[12]: 子ウインドウのフォームがWin7になる
□投稿者/ とっちゃん (518回)-(2018/09/04(Tue) 11:56:05)
No88491 (ソニン さん) に返信

> hwndはintptr、mcはSystem.Windows.Forms.MdiClientですが
> どのように変換したら良いのですか?
>
MdiClient の親クラスをたどっていくと、IWin32Window というインターフェースがあります。
このインターフェースに、Handle というプロパティがあるのでそれで取得できます。

変換する必要はありません。


> また、sbはどのように取得すれば良いですか?
>
sb は利用しませんよ。ウィンドウハンドルを特定するための方法そのものが全く違う手段に代わっています。

> SetWindowLongPtr( hwnd, GWLP_WNDPROC, proc );
>
> で
> Me.wpdがprocに変わっていますが
> procはどこで取得するのですが、
> 修正案を教えていただけないでしょうか?
>
proc は単に、書くのが面倒だったからそうしただけで、Me.wpd をセットすればOKです。

引用返信 編集キー/
■88501 / inTopicNo.16)  Re[13]: 子ウインドウのフォームがWin7になる
□投稿者/ ソニン (9回)-(2018/09/04(Tue) 12:11:27)
もしかしてこれだけで良いのでしょうか?

Dim mc As System.Windows.Forms.MdiClient = GetMdiClient(Me)

Me.wpd = New WndProcDelegate(AddressOf NewWndProc)
Me.PrevWndProc = Form0.SetWindowLongPtr(mc.Handle, GWL_WNDPROC, Me.wpd)



しかし、
3行目で

追加情報:DLL 'user32.dll' の 'SetWindowLongPtr' というエントリ ポイントが見つかりません。

というエラーが出てしまいます。


引用返信 編集キー/
■88504 / inTopicNo.17)  Re[14]: 子ウインドウのフォームがWin7になる
□投稿者/ とっちゃん (519回)-(2018/09/04(Tue) 13:00:31)
No88501 (ソニン さん) に返信
> もしかしてこれだけで良いのでしょうか?
>
> Dim mc As System.Windows.Forms.MdiClient = GetMdiClient(Me)
>
> Me.wpd = New WndProcDelegate(AddressOf NewWndProc)
> Me.PrevWndProc = Form0.SetWindowLongPtr(mc.Handle, GWL_WNDPROC, Me.wpd)
>
はい。
ですが、mc が Null になっていないことは確認したほうがいいと思います。

>
>
> しかし、
> 3行目で
>
> 追加情報:DLL 'user32.dll' の 'SetWindowLongPtr' というエントリ ポイントが見つかりません。
>
> というエラーが出てしまいます。
>
>
すっかり忘れていた。
SetWindowLongPtr は、64bit の場合だけです。

なので、IntPtr.Size = 4 で、SetWindowLong または SetWindowLongPtr を呼び出すようにしないと駄目ですね。

引用返信 編集キー/
■88507 / inTopicNo.18)  Re[15]: 子ウインドウのフォームがWin7になる
□投稿者/ ソニン (10回)-(2018/09/04(Tue) 14:14:36)
ありがとうございます。
一応、動作したように思います。

mcがnullになっていないか確認する方法に関してですが、

If mc <> Null Then
だと受け付けないですが

If mc IsNot Nothing Then

で良いのでしょうか?

また、どのような場合にNullになることがあり得ますか?
引用返信 編集キー/
■88508 / inTopicNo.19)  Re[16]: 子ウインドウのフォームがWin7になる
□投稿者/ ソニン (11回)-(2018/09/04(Tue) 14:16:49)
うまくいったと思いましたが勘違いでした。


Dim mc As System.Windows.Forms.MdiClient = GetMdiClient(Me)

If mc IsNot Nothing Then

Me.wpd = New WndProcDelegate(AddressOf NewWndProc)

If (IntPtr.Size = 4) Then
Me.PrevWndProc = Form0.SetWindowLong(mc.Handle, GWL_WNDPROC, Me.wpd)
Else
Me.PrevWndProc = Form0.SetWindowLongPtr(mc.Handle, GWL_WNDPROC, Me.wpd)
End If

End If

とやってみたのですが、
追加情報:DLL 'user32.dll' の 'SetWindowLongPtr' というエントリ ポイントが見つかりません。

というエラーが出てしまいます。
引用返信 編集キー/
■88509 / inTopicNo.20)  Re[17]: 子ウインドウのフォームがWin7になる
 
□投稿者/ とっちゃん (520回)-(2018/09/04(Tue) 15:29:34)
No88507 (ソニン さん) に返信

> mcがnullになっていないか確認する方法に関してですが、
>
> If mc <> Null Then
> だと受け付けないですが
>
> If mc IsNot Nothing Then
>
> で良いのでしょうか?
>

「受け付けない」というのがどういう状態を指しているのかわかりませんが
うまくいくほうを採用すればいいと思います。

> また、どのような場合にNullになることがあり得ますか?

MdiClientが作られる前の状況で呼び出せばNullになります。

まぁ、めったにないですが、エラーチェックは自分のプログラムが安全に動くために
強いてはのちのユーザーサポートを軽減するためにも常に心が変えておくことをお勧めします。



No88508 (ソニン さん) に返信

> 追加情報:DLL 'user32.dll' の 'SetWindowLongPtr' というエントリ ポイントが見つかりません。
>
> というエラーが出てしまいます。

pinvoke.net という、P/Invoke(プラットフォーム呼び出し)コードが載ってるサイトを紹介しておきます。

やってることは同じに見えますが、これでどうかなどを確認してみてください。

http://www.pinvoke.net/default.aspx/user32.setwindowlong


引用返信 編集キー/

このトピックをツリーで一括表示

次の20件>
トピック内ページ移動 / << 0 | 1 >>

管理者用

- Child Tree -