Solved

Keeping Window on the Screen

Posted on 2001-08-14
22
166 Views
Last Modified: 2010-05-02
I would like to allow a user to move a window but not to drag it off the screen.

I dont want to use a timer to check the window state and I have tried to do this with the paint event but paint doesnt fire when the window is being dragged off, only on.

I have looked but fail to see an API to limit the window drag area.

Thanks for any help.
0
Comment
Question by:woodsrr
22 Comments
 

Expert Comment

by:withAtwist
ID: 6384488
.
0
 
LVL 8

Expert Comment

by:DennisBorg
ID: 6384590
There is a window message you can trap, which you can use to restrict the window's minimum and maximum size, so that the user cannot resize the window too small or too big. I'm not sure, but I think that within that same mechanism, you can specify the limits of where the form can be moved within.

But there is another method you can use; either way, you have to subclass your window.

This other method would be to trap for the WM_MOVE message, and then check to see if the form is off the edge of the screen. For example:

         With Form1
            If .Left + .Width > Screen.Width Then .Left = Screen.Width - .Width
            If .Left < 0 Then .Left = 0
            If .Top + .Height > Screen.Height Then .Top = Screen.Height - .Height
            If .Top < 0 Then .Top = 0
         End With


Are you familiar with subclassing, and how you'd go about that?


-Dennis Borg
0
 
LVL 1

Expert Comment

by:jendrix
ID: 6384591
maybe not what you want...
If you used an mdi-form the window that is an mdi child can not be moved outside the mdi form
0
 
LVL 8

Expert Comment

by:DennisBorg
ID: 6384653
jendrix:

>maybe not what you want...
>If you used an mdi-form the window that is an mdi child
>can not be moved outside the mdi form

I don't think that MDI Parent windows and MDI Child windows are being used here.

woodsrr does describe the form being dragged off the *screen*, not off the parent form.


-Dennis Borg
0
 

Author Comment

by:woodsrr
ID: 6384801
Trapping the window move message is what I need, not clear on how to do that, but will look into it.
0
 

Author Comment

by:woodsrr
ID: 6384833
Trapping the window move message is what I need, not clear on how to do that, but will look into it.
0
 

Author Comment

by:woodsrr
ID: 6384841
Ok, I read that subclassinc would require me to create a DLL using C or C++ or a third party package such as Desaware's Spy.  Since my C is rusty at best, what if any probles are there in using the Desaware Spy, or is there a better way?
0
 
LVL 16

Expert Comment

by:Richie_Simonetti
ID: 6384875
You can subclass without any external dll(almost).
0
 

Author Comment

by:woodsrr
ID: 6384892
Ok, I read that subclassinc would require me to create a DLL using C or C++ or a third party package such as Desaware's Spy.  Since my C is rusty at best, what if any probles are there in using the Desaware Spy, or is there a better way?
0
 

Author Comment

by:woodsrr
ID: 6384924
They way I have works pretty good, was just looking for a better way.  Thought there must be an API that does this?  My window doesnt have a title bar anyways so they have to click and drag on the form.  Here is how I'm doing it now.

Dim miX As Integer
Dim miY As Integer

Private Sub Form_MouseDown(Button As Integer, Shift As Integer, X As Single, Y As Single)
    If Button = vbLeftButton Then
        miX = X
        miY = Y
    End If
End Sub

Private Sub Form_MouseMove(Button As Integer, Shift As Integer, X As Single, Y As Single)
    If Button = vbLeftButton Then
        If (Me.Left + X - miX > 0) Then
            If (Me.Left + X + Me.Width - miX < Screen.Width) Then
                Me.Left = Me.Left + (X - miX)
            Else
                Me.Left = Screen.Width - Me.Width
            End If
        Else
            Me.Left = 0
        End If
       
        If (Me.Top + Y - miY > 0) Then
            If (Me.Top + Y + Me.Height - miY < Screen.Height) Then
                Me.Top = Me.Top + (Y - miY)
            Else
                Me.Top = Screen.Height - Me.Height
            End If
        Else
            Me.Top = 0
        End If
    End If
End Sub
0
 
LVL 8

Expert Comment

by:DennisBorg
ID: 6384937
woodsrr:

Which version of VB are you using? If you have VB5 or VB6, you can subclass your own window without third-party controls or DLL's (via the AddressOf operator, SetWindowLong(), and some code in a Standard Code Module).

-Dennis Borg
0
Maximize Your Threat Intelligence Reporting

Reporting is one of the most important and least talked about aspects of a world-class threat intelligence program. Here’s how to do it right.

 
LVL 8

Accepted Solution

by:
DennisBorg earned 100 total points
ID: 6384962
(first a quick note -- when subclassing your form this way, you cannot break your code and trace line-by-line. You also cannot use the Stop button on the VB menubar. Doing so while you have activated subclassing will cause your program to crash. *ALWAYS* save your work before running/testing the program)


To subclass your form, you need to add the following to a Standard Code Module:


-----------------------------------------------------------
Option Explicit

Public OldWinProc As Long
Public OldhWnd    As Long

Public Const GWL_WNDPROC = (-4)
Public Const WM_MOVE = &H3

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 Declare Function DefWindowProc Lib "user32" Alias "DefWindowProcA" ( _
   ByVal hWnd As Long, _
   ByVal wMsg As Long, _
   ByVal wParam As Long, _
   ByVal lParam As Long _
) As Long

Function MyWinProc(ByVal hWnd As Long, ByVal wMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
   Select Case wMsg:
      Case WM_MOVE:
         With Form1
            If .Left + .Width > Screen.Width Then .Left = Screen.Width - .Width
            If .Left < 0 Then .Left = 0
            If .Top + .Height > Screen.Height Then .Top = Screen.Height - .Height
            If .Top < 0 Then .Top = 0
         End With
      Case Else:
         MyWinProc = CallWindowProc(OldWinProc, hWnd, wMsg, wParam, lParam)
   End Select
End Function

Sub SubClassWin(ByVal hWnd As Long)
   OldhWnd = hWnd
   OldWinProc = SetWindowLong(hWnd, GWL_WNDPROC, AddressOf MyWinProc)
End Sub


Sub UnSubClassWin()
   SetWindowLong OldhWnd, GWL_WNDPROC, OldWinProc
End Sub
-----------------------------------------------------------




Then, in your form's Load event:

   SubClassWin Me.hWnd



And in your form's Unload event:

   UnSubClassWin


-Dennis Borg
0
 
LVL 8

Expert Comment

by:DennisBorg
ID: 6384967
Of course, in the code below, you'd want to change "Form1" to the actual name of your form.

     Case WM_MOVE:
        With Form1
           If .Left + .Width > Screen.Width Then .Left = Screen.Width - .Width
           If .Left < 0 Then .Left = 0
           If .Top + .Height > Screen.Height Then .Top = Screen.Height - .Height
           If .Top < 0 Then .Top = 0
        End With


0
 

Author Comment

by:woodsrr
ID: 6384973
They way I have works pretty good, was just looking for a better way.  Thought there must be an API that does this?  My window doesnt have a title bar anyways so they have to click and drag on the form.  Here is how I'm doing it now.

Dim miX As Integer
Dim miY As Integer

Private Sub Form_MouseDown(Button As Integer, Shift As Integer, X As Single, Y As Single)
    If Button = vbLeftButton Then
        miX = X
        miY = Y
    End If
End Sub

Private Sub Form_MouseMove(Button As Integer, Shift As Integer, X As Single, Y As Single)
    If Button = vbLeftButton Then
        If (Me.Left + X - miX > 0) Then
            If (Me.Left + X + Me.Width - miX < Screen.Width) Then
                Me.Left = Me.Left + (X - miX)
            Else
                Me.Left = Screen.Width - Me.Width
            End If
        Else
            Me.Left = 0
        End If
       
        If (Me.Top + Y - miY > 0) Then
            If (Me.Top + Y + Me.Height - miY < Screen.Height) Then
                Me.Top = Me.Top + (Y - miY)
            Else
                Me.Top = Screen.Height - Me.Height
            End If
        Else
            Me.Top = 0
        End If
    End If
End Sub
0
 

Expert Comment

by:akkalam
ID: 6384974
Hi,
 u can do this by using Timer control. Set Timer's Interverl to 3 or 4. And write the code in it's event.
With Form1
 If .Left + .Width > Screen.Width Then .Left = Screen.Width - .Width
 If .Left < 0 Then .Left = 0
 If .Top + .Height > Screen.Height Then .Top = Screen.Height - .Height
 If .Top < 0 Then .Top = 0
 End With

I am not sure, u just check out
Thanks

0
 

Author Comment

by:woodsrr
ID: 6385071
They way I have works pretty good, was just looking for a better way.  Thought there must be an API that does this?  My window doesnt have a title bar anyways so they have to click and drag on the form.  Here is how I'm doing it now.

Dim miX As Integer
Dim miY As Integer

Private Sub Form_MouseDown(Button As Integer, Shift As Integer, X As Single, Y As Single)
    If Button = vbLeftButton Then
        miX = X
        miY = Y
    End If
End Sub

Private Sub Form_MouseMove(Button As Integer, Shift As Integer, X As Single, Y As Single)
    If Button = vbLeftButton Then
        If (Me.Left + X - miX > 0) Then
            If (Me.Left + X + Me.Width - miX < Screen.Width) Then
                Me.Left = Me.Left + (X - miX)
            Else
                Me.Left = Screen.Width - Me.Width
            End If
        Else
            Me.Left = 0
        End If
       
        If (Me.Top + Y - miY > 0) Then
            If (Me.Top + Y + Me.Height - miY < Screen.Height) Then
                Me.Top = Me.Top + (Y - miY)
            Else
                Me.Top = Screen.Height - Me.Height
            End If
        Else
            Me.Top = 0
        End If
    End If
End Sub
0
 

Author Comment

by:woodsrr
ID: 6385112
Akkalam:  As I stated in the question, I dont want to use a time control and the way I'm currently doing it is better in my opinion.

DennisBorg:  I have used AddressOf for fast parsing, and graphics but never though to use it here and I'm not 100 percent clear what this does.  However I tried the code you included and got an error: Invalid Used of AddressOf and it highlights this line:
 OldWinProc = SetWindowLong(hWnd, GWL_WNDPROC, AddressOf MyWinProc)

I started a new program, cut and pasted your code, moving the public const and declares to a Module.  Not sure what I'm doing wrong.  Going to go back and look at a VB Article on AddressOf and see if I can figure out what you are trying to tell me.
0
 

Author Comment

by:woodsrr
ID: 6385119
Sorry for the duplicate post..... Darn Refresh button...
0
 

Author Comment

by:woodsrr
ID: 6385144
Ok, I just reread.  The who code goes in a module. I no longer get the error.  But I doesnt keep the form on the screen.
0
 

Author Comment

by:woodsrr
ID: 6385149
OK, yes it does.  And it does crash VB.  I'll keep this in mind but will probably stick to the way I'm doing it now.  Thanks for your time all.
0
 

Author Comment

by:woodsrr
ID: 6385154
Answer was a B to C but no fault of DennisBorg, just the way VB is.  Effort was an 'A'.  Thanks.
0
 
LVL 8

Expert Comment

by:DennisBorg
ID: 6385236
The AddressOf operator returns the Address Of the specified function; but this only works with functions that are in Standard Code Modules, *NOT* in any Object Code Modules (such as your form's code module).

In other words, you cannot have the MyWinProc() function in a Form Code Module, or in a Class Code Module, or anywhere, except in a Standard Code Module (.BAS)


You will want to close your form nomally (by clicking the 'X', or by your program Unloading the form), otherwise it will crash (as I've stated before, and as you've experienced personally)

The reason is that the Windows Operating System is going to call your Window Procedure (MyWinProc) to pass Window Messages to it. When you break your code so that you can trace line by line, Windows cannot invoke that function, hence it crashes.

Or if you click the "Stop" button on the VB menu bar, then your Form Unload event does not happen, which means your form does not get UNsubclassed. Again, Windows tries to call the Windows Procedure to your own function, which is no longer around, which causes a crash.

When you subclass a window, you are rerouting window messages, so that instead of them being sent to the Default Window Handler, they are sent to your own custom window handler (MyWinProc). Anytime you impede or prevent the ability of the Window Handler from processing messages sent to it by the Operating System (MS Windows), you are going to have problems.


I hope that makes sense.


-Dennis Borg
0

Featured Post

Top 6 Sources for Identifying Threat Actor TTPs

Understanding your enemy is essential. These six sources will help you identify the most popular threat actor tactics, techniques, and procedures (TTPs).

Join & Write a Comment

If you have ever used Microsoft Word then you know that it has a good spell checker and it may have occurred to you that the ability to check spelling might be a nice piece of functionality to add to certain applications of yours. Well the code that…
If you need to start windows update installation remotely or as a scheduled task you will find this very helpful.
Get people started with the process of using Access VBA to control Outlook using automation, Microsoft Access can control other applications. An example is the ability to programmatically talk to Microsoft Outlook. Using automation, an Access applic…
This lesson covers basic error handling code in Microsoft Excel using VBA. This is the first lesson in a 3-part series that uses code to loop through an Excel spreadsheet in VBA and then fix errors, taking advantage of error handling code. This l…

708 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

17 Experts available now in Live!

Get 1:1 Help Now