|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Visual Basic Subclassing Routines WM_NCHITTEST: Simulating a Non-Client Action to Move a Form |
||
Posted: | Wednesday July 1, 1998 | |
Updated: | Monday December 26, 2011 | |
Applies to: | VB5, VB6 | |
Developed with: | VB6, Windows 98 | |
OS restrictions: | None | |
Author: | VBnet - Randy Birch | |
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. |
|
|
|
|||||
|
|||||
|
|||||
Copyright ©1996-2011 VBnet and Randy Birch. All Rights Reserved. |