dcsimg
CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Results 1 to 6 of 6

Thread: Constraing proportions

  1. #1
    Join Date
    Jul 2005
    Location
    Plzeň, Czech Republic
    Posts
    94

    Unhappy Constraing proportions

    Is there a way how to limit size of a window? I want sizeable window but lets say I want its width to be at least 1000 twips.

    I surely can use this construct, but it looks ugly like ****... is there any other way?

    Private Sub Form_Resize()
    If frmMain.Width < 1000 Then frmMain.Width = 1000
    End Sub

    I also need suggestion how to create those neat CODE windows here at formus. I don't want to insert code as regular text anymore.

    Thanks for any help ;-)
    Last edited by jsiii; September 27th, 2005 at 05:03 AM.

  2. #2
    Join Date
    Jul 2005
    Location
    Plzeň, Czech Republic
    Posts
    94

    Thumbs down Re: Constraing proportions

    What??? he11 is restricted word??? Geez...
    Last edited by jsiii; September 27th, 2005 at 11:34 AM.

  3. #3
    Join Date
    Mar 2005
    Location
    Nottingham, UK
    Posts
    665

    Re: Constraing proportions

    Hi jsiii,

    The only way I am aware of managing window sizes without the 'ugly as he11' flickering that occurs using the from resize event is to subclass.

    This code should do the trick, but beware - please make sure that you save everything you are doing before trying to execute this - an error in subclassing often brings down your entire VB development environment. I've also heard it can bring down Windows too, but I haven't seen this happen.

    Put the following in a module:

    Code:
    Option Explicit
    
    Public Const GWL_WNDPROC = (-4)
    Public ProcOld As Long
    
    '**Windows API Call for catching messages**
    Public Declare Function SetWindowLong Lib "user32" Alias "SetWindowLongA" _
    (ByVal hwnd As Long, ByVal nIndex As Long, ByVal dwNewLong As Long) As Long
    
    '**Windows API call for calling window procedures**
    Public Declare Function CallWindowProc Lib "user32" Alias "CallWindowProcA" _
    (ByVal lpPrevWndFunc As Long, _
    ByVal hwnd As Long, _
    ByVal Msg As Long, _
    ByVal wParam As Long, _
    lParam As MINMAXINFO) As Long
    
    Public Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" _
    (Destination As Any, Source As Any, ByVal Length As Long)
    
    Type POINTAPI
        x As Long
        y As Long
    End Type
    
    Type MINMAXINFO
        ptReserved As POINTAPI
        ptMaxSize As POINTAPI
        ptMaxPosition As POINTAPI
        ptMinTrackSize As POINTAPI
        ptMaxTrackSize As POINTAPI
    End Type
    
    'Windows messages constants
    Public Const WM_GETMINMAXINFO As Long = &H24
    Public Const WM_NCDESTROY = &H82
    
    
    Public Function NewWindowProc(ByVal hwnd As Long, ByVal WMsg As Long, _
    ByVal wParam As Long, lParam As MINMAXINFO) As Long
    
    '***WARNING***
    'do not attempt to debug this procedure!!
    
        Select Case WMsg
        
        Case Is = WM_NCDESTROY 'if being destroyed, restore original window proc
                SetWindowLong hwnd, GWL_WNDPROC, ProcOld
        
        Case Is = WM_GETMINMAXINFO 'manage form position
            
            Dim MinMax As MINMAXINFO
            
            CopyMemory MinMax, ByVal lParam, len(MinMax)
            
            '**THIS IS THE BIT THAT YOU'RE INTERESTED IN - SET THE VALUES THAT SUIT YOU HERE
            With MinMax
                'set the width of the form when it's maximized
                .ptMaxSize.x = 500&
                'set the height of the form when it's maximized
                .ptMaxSize.y = 400&
                
                'set the Left of the form when it's maximized
                .ptMaxPosition.x = 100&
                'set the Top of the form when it's maximized
                .ptMaxPosition.y = 100&
                
                'set the max width that the user can drag the form
                .ptMaxTrackSize.x = .ptMaxSize.x
                'set the max height that the user can drag the form
                .ptMaxTrackSize.y = .ptMaxSize.y
                
                'set the min width that the user can drag the form
                .ptMinTrackSize.x = 150&
                'set the min height that the user can drag the form
                .ptMinTrackSize.y = 100&
            End With
            
            CopyMemory ByVal lParam, MinMax, len(MinMax)
            NewWindowProc = False
            
        case else
            '**VERY IMPORTANT**
            'pass all messages on to VB and then return the value to windows
            'control MUST be returned to VB and Windows or bad things will happen!
            NewWindowProc = CallWindowProc(ProcOld, hwnd, WMsg, wParam, lParam)
    
        End Select
    
    End Function
    Then place a command button called cmdOnOff on a form and add the following:

    Code:
    Option Explicit
    
    Private clickOff As Boolean
    
    Private Sub cmdOnOff_Click()
    clickOff = Not clickOff
    
        If clickOff Then 'turn subclassing off
            cmdOnOff.Caption = "ON"
            Call SetWindowLong(hwnd, GWL_WNDPROC, ProcOld)
        Else 'turn subclassing on
            cmdOnOff.Caption = "OFF"
            ProcOld = SetWindowLong(hwnd, GWL_WNDPROC, AddressOf NewWindowProc)
        End If
        
    End Sub
    
    Private Sub Form_Load()
        On Error Resume Next
        'saves the previous window message handler. Always restore this value
        'AddressOf command sends the address of the NewWindowProc procedure
        'to windows
        ProcOld = SetWindowLong(hwnd, GWL_WNDPROC, AddressOf NewWindowProc)
        
    End Sub
    
    Private Sub Form_Unload(Cancel As Integer)
        'give message processing control back to VB
        'if you don't do this there will be trouble!!!
        Call SetWindowLong(hwnd, GWL_WNDPROC, ProcOld)
    End Sub
    I was playing with this earlier, but whilst the maximum form width and height settings work fine, I couldn't get the minimum settings working, which seems strange as the subclassing appears to be doing exactly what it should. Maybe someone else can see why the minimum x and y won't take... (The above code has been edited and is fixed now. Should work beautifully.)

    Oh, to insert these code windows, you just use html like tags. If you scroll to the bottom of the Forum page, there is a box entitled Posting Rules, in which you'll find a link to vbcode. Everything is explained there.

    ...
    Last edited by Dan_H; September 27th, 2005 at 10:14 AM.

  4. #4
    Join Date
    Mar 2005
    Location
    Nottingham, UK
    Posts
    665

    Re: Constraing proportions

    Right, a quick trip to MSDN and a minor tweak and the above code does work fully. You can limit both MIN and MAX form dimensions as you drag.

    I only include the button so you can switch it on and off; you don't need this, just keep the code for the form_load and form_unload events for your own implementation and specify the values for form width and height in the NewWindowProc procedure.

    Oh, and also bear in mind that the dimension values are in Pixels when using API calls. You don't appear to need to have the form's scalemode set to Pixels for this to work, but its probably best to.
    Last edited by Dan_H; September 27th, 2005 at 10:10 AM.

  5. #5
    Join Date
    Jul 2005
    Location
    Plzeň, Czech Republic
    Posts
    94

    Re: Constraing proportions

    Wow, nice code, thank you :-) But pretty complicated for such simple task :-( I guess VB lost again :-/

  6. #6
    Join Date
    Mar 2005
    Location
    Nottingham, UK
    Posts
    665

    Re: Constraing proportions

    It is pretty complicated, but there are some things that VB doesn't do very well on its own. Your above problem is one of them. The Form_Resize event fires after windows has done its painting of screen objects, therefore any attempt to set limits will always be a fraction behind, causing the awful flickering that you've experienced.

    There are a lot of messages that Windows sends to objects such as forms that VB won't normally expose to us; effectively VB just discards them. The above code replaces the message handling routine that the VB form normally uses with a custom one, in which we can intercept the Windows messages, look for the ones we want, and manipulate them accordingly. All of this happens before windows or VB can do any of its form painting, which is why this method produces rock solid results with no hint of juddering or flickering.

    There are plenty of great articles online about subclassing where you can learn more if you wish. If not, the majority of the code is tucked neatly into a module anyway, so for the most part you don't have to worry too much about it. Just be careful with debugging - make sure you don't debug the custom NewWindowProc as there are far too many messages flying around for VB's debugger to handle!

    ...

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  


Windows Mobile Development Center


Click Here to Expand Forum to Full Width




On-Demand Webinars (sponsored)