2019年5月7日火曜日

VB Form 等の縦横比を固定 Form 編

VB.net から Windows API を叩く ... 。
う~ん、 難しい事は分からないので、 積極的には使っていません。
でも、 Form 等で その縦横比を固定したい とすれば、
API を叩くのが 正解 ですね。



Form 等の縦横比を固定したい!。
そんなケースは、私にとっては、稀なのです。
と言うか、今回が、初めてでしょう。

大抵のケースでは、縦横の既定・最大・最小を定義すれば、
後は、 コードでの、Controls 設定で何とかなります。
良く考えられているなぁ~、と言うのが、その感想です。
そう。  縦横比に拘る事は、ほぼ、ありません。

今回、画像を背景に貼り付けたもので、
サイズをユーザーが弄った場合、
折角の画像が 不憫! になるので、
何とかしたいとは、ずっと、思っていました。

そう、画像は、 Zooming 指定 つまり 正確には StretchImage なので、
自由に大きさが可変になっているのです。
単なる幾何学模様や、抽象的な画像なら、
縦横比が元から崩れ様が、大きな問題にはなりませんが、
具体的なものや人では、違和感が騒ぎ出して仕舞います。
そして、双方を自由に選択出来るものですから、もう、てんやわんや。

  単純には、StretchImage を Zoom に切り替えれば OK ですが、
  この画像は、元々、空白を埋める為に設置してあるので、 そうもいかず ... 。

  欲しいのは、結局、Form 等の 縦横比 固定 なのです。

其処で、Internet で検索を掛けると、
C# で記述された、 Windows API を叩くコードを見付けました。
ありがたいですね。
これで、楽が出来ます。
但し、Form のみ! です。

本番用は 入り組んだスパゲッティーコードの大盛り! なので、
サンプル(テスト)用に、単純な例で 検証 します。

Form 前提 として、
Form をふたつ用意し、
片方から2番目を呼び出します。
最終目的は、
2番目のある条件下でのみ、Form 縦横比を固定する事にします。
条件は、単純に、CheckBox の Checked の値で 代替 します。

先ずは、
C# > VB.net に置き換えたコードが正常に動くか否かのチェックです。

こんなコードになります。  Form2

 Public Class Form2
    'Fixed Form W/H SizeRatio (Sample = 4:3)
    Private fixedRate As Double = (CType(4 / 3, Double))
    Private WM_SIZING As Integer = 532
    Private WMSZ_LEFT As Integer = 1
    Private WMSZ_RIGHT As Integer = 2
    Private WMSZ_TOP As Integer = 3
    Private WMSZ_TOPLEFT As Integer = 4
    Private WMSZ_TOPRIGHT As Integer = 5
    Private WMSZ_BOTTOM As Integer = 6
    Private WMSZ_BOTTOMLEFT As Integer = 7
    Private WMSZ_BOTTOMRIGHT As Integer = 8

    Structure RECT
        Public left As Integer
        Public top As Integer
        Public right As Integer
        Public bottom As Integer
    End Structure

    Private Sub Form2_Load(sender As Object, e As EventArgs) Handles MyBase.Load

    End Sub

    Protected Overrides Sub WndProc(ByRef m As Message)

        Select Case (m.Msg)
            Case WM_SIZING

                Dim r As RECT = CType(System.Runtime.InteropServices.Marshal.PtrToStructure(m.LParam, GetType(RECT)), RECT)
                Dim w As Integer = (r.right _
                            - (r.left _
                            - (Size.Width - ClientSize.Width)))
                Dim h As Integer = (r.bottom _
                            - (r.top _
                            - (Size.Height - ClientSize.Height)))
                Dim dw As Integer = (CType(((h * fixedRate) _
                            + 0.5), Integer) - w)
                Dim dh As Integer = (CType(((w / fixedRate) _
                            + 0.5), Integer) - h)
                Select Case (m.WParam.ToInt32)
                    Case WMSZ_TOP, WMSZ_BOTTOM
                        r.right = (r.right + dw)
                    Case WMSZ_LEFT, WMSZ_RIGHT
                        r.bottom = (r.bottom + dh)
                    Case WMSZ_TOPLEFT
                        If (dw > 0) Then
                            r.left = (r.left - dw)
                        Else
                            r.top = (r.top - dh)
                        End If

                    Case WMSZ_TOPRIGHT
                        If (dw > 0) Then
                            r.right = (r.right + dw)
                        Else
                            r.top = (r.top - dh)
                        End If

                    Case WMSZ_BOTTOMLEFT
                        If (dw > 0) Then
                            r.left = (r.left - dw)
                        Else
                            r.bottom = (r.bottom + dh)
                        End If

                    Case WMSZ_BOTTOMRIGHT
                        If (dw > 0) Then
                            r.right = (r.right + dw)
                        Else
                            r.bottom = (r.bottom + dh)
                        End If

                End Select

                System.Runtime.InteropServices.Marshal.StructureToPtr(r, m.LParam, False)

            Case Else
                MyBase.WndProc(m)
        End Select

    End Sub

End Class

差し当たり、コードが正常に動くか、確認します。
問題無い様ですね。
呼び出し元の Form1 では、変更を受けていない為、挙動は 何時もの通り です。
From2 のみ、縦横比固定で、サイズ可変となっていますね。

  此処では示しませんが、同様に、Form3 を追加しても、
  其処に API 叩き を記述しなければ、挙動はForm1 と同じです。
  そう、 Overrides した Form2 のみ挙動が変わっているのが確認出来ます。
  Windows API にお詳しければ、当たり前の動きだと思いますが、
  見知らぬ内容のコードを自分用に転用する場合には、こうした確認作業は重要ですね。.

さて、ここから、一定の条件下のみ を満たす様に弄ります。

今回採用したコードを眺めていれば、自ずと、どうすれば良いか、教えてくれます。
Case WM_SIZING の条件分岐の後に、
目的の CheckBox の値による 更なる条件分岐 を加えれば良いのですね。
値が False なら、
此処でのコード部分を実行させ、
値が False なら、
最下の Case Else 同様に、 MyBase.WndProc(m) を加えれば良いでしょう。

コードそのもののご紹介は省略させて戴きます。
お分かりになりますよね!。

これで、 CheckBox がチェックされた場合のみ、 縦横比固定 の Form サイズ可変 です。


さて、この様に書き進めて、さぁ本番と言う時に、気付くのです。
件の App. は ... あろう事か ... WPF ... 。  ふぅ。
で、 次回 に続きます。




0 件のコメント:

コメントを投稿