Prerequisites |
VB5 or VB6. |
|
In
an application presenting a title-less form, it may be desirable to allow the user to reposition the form by clicking anywhere
on the form body and
dragging. While one method for accomplishing this was presented in DrawFocusRect: Simulating Non-Client Form Movement, VB5/VB6 and subclassing provides another means.
This demo subclasses and captures the mouse click on a
form. Normally, this action generates a HTCLIENT message in Windows,
but by changing this message to HTCAPTION then returning this value to Windows for
subsequent processing, we can fool Windows into thinking that the mouse click occurred on the caption
area of the form. Thus dragging while holding the mouse moves the form as though the
title bar had been clicked and dragged.
It is not necessary to remove the
title bar for this to work; the
technique can also be applied to a normal form where the ability to move it wherever it is clicked is desired. Note that in this code
movement can not be achieved when clicking the button control, although clicking any lightweight control
that may be on the form, e.g. a label, shape, line or image control -
will pass the
message through and allow form repositioning.
This example was provided to VBnet by
Domenico
Statuto, author of the CCRP
Extended FileDialogs Control. |
|
BAS
Module Code |
|
Place the following code into the general declarations
area of a bas module: |
|
Option Explicit
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' Copyright ©1996-2011 VBnet/Randy Birch, All Rights Reserved.
' Some pages may also contain other copyrights by the author.
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' Distribution: You can freely use this code in your own
' applications, but you may not reproduce
' or publish this code on any web site,
' online service, or distribute as source
' on any media without express permission.
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Public defWindowProc As Long
Public Const GWL_WNDPROC As Long = (-4)
Public Const WM_NCHITTEST As Long = &H84
Public Const HTCAPTION As Long = 2
Public Const HTCLIENT As Long = 1
Public Declare Function GetWindowLong Lib "user32" _
Alias "GetWindowLongA" _
(ByVal hwnd As Long, _
ByVal nIndex As Long) As Long
Public Declare Function SetWindowLong Lib "user32" _
Alias "SetWindowLongA" _
(ByVal hwnd As Long, _
ByVal nIndex As Long, _
ByVal dwNewLong As Long) As Long
Public Declare Function CallWindowProc Lib "user32" _
Alias "CallWindowProcA" _
(ByVal lpPrevWndFunc As Long, _
ByVal hwnd As Long, _
ByVal Msg As Long, _
ByVal wParam As Long, _
ByVal lParam As Long) As Long
Public Function WindowProc(ByVal hwnd As Long, _
ByVal Msg As Long, _
ByVal wParam As Long, _
ByVal lParam As Long) As Long
'Subclass form to trap messages
On Error Resume Next
Dim retVal As Long 'Where on the form is the mouse?
Dim Mouse_X As Long 'Mouse coordinates
Dim Mouse_Y As Long
'First let the original Window Procedure process the message.
'CallWindowProc returns the part of the form the mouse is on.
retVal = CallWindowProc(defWindowProc, _
hwnd, _
Msg, _
wParam, _
lParam)
'What message received?
Select Case Msg
Case WM_NCHITTEST 'Every mouse action
'in lParam there are the mouse co-ordinates
'for info only
Mouse_X = LoWord(lParam)
Mouse_Y = HiWord(lParam)
Form1.Label1.Caption = "X: " & Mouse_X & vbCrLf & _
"Y: " & Mouse_Y
'If mouse on client area, tell Windows the mouse is
'on the caption bar!
If retVal = HTCLIENT Then 'action on client area
retVal = HTCAPTION 'tell Windows its the caption
End If
Case Else
'Other WM_xxx messages you want to intercept
'Act as appropriate
End Select
'return the value HTCAPTION to Windows
WindowProc = retVal
End Function
Public Function HiWord(dw As Long) As Integer
If dw And &H80000000 Then
HiWord = (dw \ 65535) - 1
Else
HiWord = dw \ 65535
End If
End Function
Public Function LoWord(dw As Long) As Integer
If dw And &H8000& Then
LoWord = &H8000& Or (dw And &H7FFF&)
Else
LoWord = dw And &HFFFF&
End If
End Function |
|
Form
Code |
|
Create a borderless form, and add any controls desired to
test their effect. Just be sure to include a means to invoke the unload method of the form to unsubclass the form before ending (ie the Exit
button above), and a Label (Label1) Add the following code: |
|
Option Explicit
Private Sub Command1_Click()
Unload Me
End Sub
Private Sub Form_Load()
'Begin the subclassing of Form1 by passing the
'address of our new Window Procedure. SetWindowLong
'returns the address of the original Window Procedure,
'so we store it in a global variable to restore
'when stopping the subclassing (typically, in the
'Unload event).
defWindowProc = SetWindowLong(Form1.hwnd, _
GWL_WNDPROC, _
AddressOf WindowProc)
End Sub
Private Sub Form_Unload(Cancel As Integer)
'restore the original Window Procedure
'before unloading the form, or GPF will occur
If defWindowProc Then
Call SetWindowLong(Form1.hwnd, _
GWL_WNDPROC, _
defWindowProc)
defWindowProc = 0
End If
End Sub |
|
Comments |
Save then run the project. Clicking anywhere on the form
or lightweight control and dragging will move the form as though the
title bar had been used. |
|