- PR -

Messengerのような画面制御について

投稿者投稿内容
れい
ぬし
会議室デビュー日: 2005/11/01
投稿数: 346
投稿日時: 2007-06-09 22:20

ALTによるボーダーの切り替え、移動、サイズ変更の最小コードです。
ついでにフォームをクリックすると移動できるようにしてあります。

メニューはMainMenuコントロールを使わないとだめです。

コード:
Public Class Form1

    Private Const WM_NCHITTEST As Integer = &H84
    Private Const HTERROR = (-2)
    Private Const HTTRANSPARENT = (-1)
    Private Const HTNOWHERE = 0
    Private Const HTCLIENT = 1
    Private Const HTCAPTION = 2
    Private Const HTSYSMENU = 3
    Private Const HTGROWBOX = 4
    Private Const HTSIZE = HTGROWBOX
    Private Const HTMENU = 5
    Private Const HTHSCROLL = 6
    Private Const HTVSCROLL = 7
    Private Const HTMINBUTTON = 8
    Private Const HTMAXBUTTON = 9
    Private Const HTLEFT = 10
    Private Const HTRIGHT = 11
    Private Const HTTOP = 12
    Private Const HTTOPLEFT = 13
    Private Const HTTOPRIGHT = 14
    Private Const HTBOTTOM = 15
    Private Const HTBOTTOMLEFT = 16
    Private Const HTBOTTOMRIGHT = 17
    Private Const HTBORDER = 18
    Private Const HTREDUCE = HTMINBUTTON
    Private Const HTZOOM = HTMAXBUTTON
    Private Const HTSIZEFIRST = HTLEFT
    Private Const HTSIZELAST = HTBOTTOMRIGHT

    Public Property ClientRectangleOnly() As Boolean
        Get
            Return Me.Region IsNot Nothing
        End Get
        Set(ByVal value As Boolean)
            If value = Me.ClientRectangleOnly Then Exit Property
            If Me.Region Is Nothing Then
                Dim r As Rectangle
                r.X = Me.PointToScreen(Me.ClientRectangle.Location).X - Me.Left
                r.Y = Me.PointToScreen(Me.ClientRectangle.Location).Y - Me.Top
                r.Width = Me.ClientRectangle.Width
                r.Height = Me.ClientRectangle.Height
                Me.Region = New Region(r)
            Else
                Me.Region = Nothing
            End If
        End Set
    End Property

    Protected Overrides Sub WndProc(ByRef m As System.Windows.Forms.Message)
        Select Case m.Msg
            Case WM_NCHITTEST
                Dim p As Point
                p = Me.PointToClient(New Point(m.LParam.ToInt32 Mod 65536, m.LParam.ToInt32 \\ 65536))

                If p.X > Me.ClientRectangle.Right Then Exit Select
                If p.X < Me.ClientRectangle.Left Then Exit Select
                If p.Y < Me.ClientRectangle.Top Then Exit Select
                If p.Y > Me.ClientRectangle.Bottom Then Exit Select

                If p.X < Me.ClientRectangle.Left + 5 Then
                    If p.Y < Me.ClientRectangle.Top + 5 Then
                        m.Result = HTTOPLEFT
                        Exit Sub
                    End If
                    If p.Y > Me.ClientRectangle.Bottom - 5 Then
                        m.Result = HTBOTTOMLEFT
                        Exit Sub
                    End If
                    m.Result = HTLEFT
                    Exit Sub
                End If
                If p.X > Me.ClientRectangle.Right - 5 Then
                    If p.Y < Me.ClientRectangle.Top + 5 Then
                        m.Result = HTTOPRIGHT
                        Exit Sub
                    End If
                    If p.Y > Me.ClientRectangle.Bottom - 5 Then
                        m.Result = HTBOTTOMRIGHT
                        Exit Sub
                    End If
                    m.Result = HTRIGHT
                    Exit Sub
                End If
                If p.Y < Me.ClientRectangle.Top + 5 Then
                    m.Result = HTTOP
                    Exit Sub
                End If
                If p.Y > Me.ClientRectangle.Bottom - 5 Then
                    m.Result = HTBOTTOM
                    Exit Sub
                End If

                m.Result = HTCAPTION
                Exit Sub
        End Select
        MyBase.WndProc(m)
    End Sub

    Private Sub Form1_ClientSizeChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.ClientSizeChanged
        If Me.ClientRectangleOnly Then
            Dim r As Rectangle
            r.X = Me.PointToScreen(Me.ClientRectangle.Location).X - Me.Left
            r.Y = Me.PointToScreen(Me.ClientRectangle.Location).Y - Me.Top
            r.Width = Me.ClientRectangle.Width
            r.Height = Me.ClientRectangle.Height
            Me.Region = New Region(r)
        End If
    End Sub

    Private Sub Form1_KeyDown(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyEventArgs) Handles Me.KeyDown
        If e.Alt Then
            If Me.ClientRectangleOnly Then
                Me.ClientRectangleOnly = False
            Else
                Me.ClientRectangleOnly = True
            End If
            e.Handled = True
        End If
    End Sub

End Class



extream
ベテラン
会議室デビュー日: 2005/12/26
投稿数: 83
投稿日時: 2007-06-10 14:11
れいさん、いつも丁寧な回答ありがとうございます。


いろいろアルゴリズムを教えていただき、本当に感謝しますm(__)m
私は、まだUI系のロジックはあまり組んだことがなく、ノウハウが少ないので非常に助かります。


では、まず一通り組んでから、どのような処理を行っているのかを追ってみます。
コード例の提示ありがとうございました m(__)m

extream
ベテラン
会議室デビュー日: 2005/12/26
投稿数: 83
投稿日時: 2007-06-10 16:47
れいさんに教えていただいたソースをC#に変換して実装したところ、期待どおりの動作を行っていることを確認できました。
ありがとうございます m(__)m



Windowメッセージは今まで触ったことがほとんどないので教えていただきたい点があります。

教えていただいたコードでは、クライアント領域に関しては期待とおりの動作ができるのですが、ラベルコントロールなどで動作させることができません。

現在作成しているフォームの外周に画像を貼っています。
(たとえば、左端(0,0)の位置からSize(10,Form.Height)のラベル)

このコントロール上でも、実際にフォームを操作しているようにしたいのです。
(フォーム内のすべてのコントロールではないです。)
これは、WndProc関数のCase文を増やすだけで対応できるのでしょうか?

ただ、ラベルコントロール上にマウスが来た時の
 ・Forms.Message.Msg
を調べようとしたのですが、デバッグすると常にWndProc関数が呼ばれてしまうので確認できませんでした。

指定したコントロール上でも、フォームと同じ動作を行うようにする手段はあるのでしょうか?
もしくは、そのようなことはできないのでしょうか?
れい
ぬし
会議室デビュー日: 2005/11/01
投稿数: 346
投稿日時: 2007-06-11 09:22
引用:

教えていただいたコードでは、クライアント領域に関しては期待とおりの動作ができるのですが、ラベルコントロールなどで動作させることができません。



なにがどう動作しないのかがわかりません。

引用:

現在作成しているフォームの外周に画像を貼っています。
(たとえば、左端(0,0)の位置からSize(10,Form.Height)のラベル)



画像を貼るのにラベルとは変わっていますね

引用:

このコントロール上でも、実際にフォームを操作しているようにしたいのです。
(フォーム内のすべてのコントロールではないです。)
これは、WndProc関数のCase文を増やすだけで対応できるのでしょうか?




操作透過ということかな?

引用:

ただ、ラベルコントロール上にマウスが来た時の
 ・Forms.Message.Msg
を調べようとしたのですが、デバッグすると常にWndProc関数が呼ばれてしまうので確認できませんでした。



WndProcやPaintイベント、DragDropなどのデバッグは工夫が入りますよ。
Debug.WriteLineなどを使いましょう。

引用:

指定したコントロール上でも、フォームと同じ動作を行うようにする手段はあるのでしょうか?



なにがしたいのかよくわかりませんが…
フォームと同じ動作ってなんでしょう?
コントールのクライアント領域の大きさを変えたいのですか?
コントロールが無いときと同じ動作にしたいのですか?

どちらにしろ、先ほどのコードを見ればわかりますが、
コントロールのサイズ変更したいときには
そのコントロールのWndProcでHTTOPやHTRIGHTなどを返せばいいんです。

どういった順番でWndProcが呼ばれるのかは
MSDNを見たり自分で調べたりしましょう。
extream
ベテラン
会議室デビュー日: 2005/12/26
投稿数: 83
投稿日時: 2007-06-11 09:53
れいさん、いつも丁寧な回答ありがとうございます。


>画像を貼るのにラベルとは変わっていますね

ピクチャボックスと間違えました。


説明下手ですいません。
やりたい事は、
 ・フォームの外周にピクチャボックスを配置した場合、教えていただいた
  コードではフォームサイズを変更できなかったので、フォーム外周に
  コントロールを配置しても、フォームサイズを変更できるようにしたい。
です。


れいさんのコメントに調べるにあたりヒントとなるキーワードが多々ありましたので、まず調べてみます。
extream
ベテラン
会議室デビュー日: 2005/12/26
投稿数: 83
投稿日時: 2007-06-13 10:02
みなさん、回答ありがとうございます。


現在調査中なのですが、
 ・WndProc
では、フォーム上(コントロールを除く)のイベントでしかコールされないものですよね?

れいさんのコメントの中に、
「コントロールのWndProcでHTTOPやHTRIGHTなどを返せばいいんです」
とあるのを見落としていたのですが、これはユーザコントロールを作成して、そのコントロール内でWndProcをオーバーライドすればよいのでしょうか?

それとも、わざわざユーザコントロールを作成しなくても、各コントロールのWndProcをオーバーライドできるものなのでしょうか?

ご存知の方いたら教えてください。
よろしくお願いします。
ぶさいくろう
ぬし
会議室デビュー日: 2005/11/22
投稿数: 1232
お住まい・勤務地: 川崎市(は俺も含めてロクな人間が住んでないよw)
投稿日時: 2007-06-13 11:55
継承コントロールを作ってオーバーライドすればよし。
extream
ベテラン
会議室デビュー日: 2005/12/26
投稿数: 83
投稿日時: 2007-06-13 13:52
ぶさいくろうさん、回答ありがとうございます。

「継承コントロール」で検索し、オーバーライドの方法がわかりました。
ありがとうございます。


テストPGを作成し、デバッグしている時に気づいたことがあります。

コントロールのWndProcをオーバーライドすることで、コントロール上にマウスが来たかどうかはわかるようになりました。
しかし、そのタイミングで
 ・HTRIGHT
 ・HTLEFT
を返してもマウスが「⇔」に変わりますが、フォームのサイズが変更しませんでした。
(フォーム右端に配置したコントロールの場合、フォームの外側にマウスを移動することができませんでした。)
また、コントロールのサイズも変更しませんでした。


コントロールのWndProcでイベントを取得し、アイコンを「⇔」に変え、フォームのサイズを変える事はできないのでしょうか?(フォームのWndProcを呼び出す?)

やりたい事は、以下です。
 ・下記のようにフォームの右端にピクチャボックスを配置する。
 ・ピクチャボックス上にマウスが来た場合に、フォームの横サイズを変更する

┌──────┐
|     ■|
|     ■|
|     ■|
|     ■|
└──────┘


質問ばかりですいません。。。
よろしくお願いしますm(__)m

スキルアップ/キャリアアップ(JOB@IT)