|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Visual Basic
Window/Form Routines SendMessage: Creating a Scrollable Viewport to Simulate a Scrollable Form |
||
Posted: | Sunday July 18, 2004 | |
Updated: | Monday December 26, 2011 | |
Applies to: | VB4-32, VB5, VB6 | |
Developed with: | VB6, Windows XP | |
OS restrictions: | None | |
Author: | VBnet - Randy, MSKB | |
Related: |
SendMessage: Move Controls to Simulate Form Scrolling |
|
Prerequisites | ||||||||
None. | ||||||||
|
||||||||
SendMessage: Move Controls to Simulate Form Scrolling
discussed two techniques for providing an application with functionality that VB
intrinsically lacks -
the ability to scrolling the controls on a form (as that demo showed), and this method -
creating a scrollable viewport by embedding one picture box inside another.
The concept for this is simple: control placement is restricted by the
size of the form, but when a picture box is created inside another
picture box, the innermost picture box can be resized to the maximum
allowed by Windows. When this occurs, only a portion of the entire inner
picture box is visible at any time within the base or viewport control,
thereby allowing us to reposition the top and left properties of this
inner control to simulate a scrollable viewport.
The small illustration above shows the controls required for this demo, coloured to provide clarity for the layout:
All controls that should "scroll" are placed inside the cyan picture box (named Picture2 in the demo) -- in other words, all controls to scroll must be created as child controls inside the cyan picture box. (If you can move a control you want to scroll outside the borders of the inner cyan control, then that control is not properly contained within the cyan picture box.) To keep the code simple this demo uses the inner (cyan) picture box to simply display an image that is larger than the form, resized via the cyan picture box AutoSize property. Naturally, in an application that will host other controls you will have to code the resizing of the scrollable (cyan) picture box. The viewport picture box (red) is sized to the form's client area minus the space needed to host the two scroll bars and the fake grab handle. When the user changes the scroll bars the cyan (inner) picture box hosting the graphic is repositioned through manipulation of the top and left properties to reveal different portions of the image through the red 'viewport' (Picture1 in this demo). Therefore, unlike the SendMessage: Move Controls to Simulate Form Scrolling demo this method has only one 'moving' control - the red viewport picture box. This demo is pretty closely based on the two published MS KB scrolling viewport articles, and as such has minimal error checking or optimization. Improvements can be made, and may be applicable depending on the specific use you have for this code. Note: the gripper handle in the bottom right corner is constructed using Windows' Marlett font. XP in themed mode does not use Marlett for the gripper image - on XP the gripper is a theme image rather than a font. It is possible to get the XP-style gripper (on XP machines), but the code required for this is outside the scope of this demo.
|
||||||||
BAS Module Code | ||||||||
None. | ||||||||
|
||||||||
Form Code | ||||||||
Add a picture box (Picture1) to act as the viewport (red). Inside Picture1 create a second picture box (Picture2 - cyan) to act as the container for the image or other controls as required. You can change the BackColor of these picture boxes to more easily see the effect when the form is sized larger than the viewport. Add a horizontal and vertical scrollbar (HScroll1, VScroll1) to the form, plus one final picture box (Picture3) that will become the resizing gripper handle. The position and size of these three controls on the form is of no importance as they are positioned by code. Add the following code: |
||||||||
|
||||||||
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. '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' 'flag to enables/disable the ability to 'resize the window using the fake grabber Private bWindowIsResizable As Boolean Private Const WM_NCLBUTTONDOWN = &HA1 Private Const HTBOTTOMRIGHT = 17 Private Declare Function SendMessage Lib "user32" _ Alias "SendMessageA" _ (ByVal hwnd As Long, _ ByVal wMsg As Long, _ ByVal wParam As Long, _ lParam As Any) As Long Private Declare Function ReleaseCapture Lib "user32" () As Long Private Sub Form_Load() HScroll1.Height = 255 VScroll1.Width = 255 'set flag indicating a resizable window bWindowIsResizable = (Me.BorderStyle = vbSizable) Or _ (Me.BorderStyle = vbSizableToolWindow) 'set up the picture box used to fill 'the corner between the H and V scroll 'bars, and if the window is sizable 'print a 'gripper' image to the control With Picture3 .AutoRedraw = True .AutoSize = True .ForeColor = &H80000015 .BackColor = Me.BackColor .BorderStyle = 0 .ZOrder 0 'if sizable windows print the gripper image If bWindowIsResizable Then .Font.Size = 11 .Font.Name = "Marlett" .Font.Bold = False Picture3.CurrentX = 10 Picture3.CurrentY = 10 Picture3.Print "o" End If End With With Picture1 .BorderStyle = 0 .Move 0, 0 .Cls End With With Picture2 'inner (cyan) picture box 'as we're loading an image, expand pix2 'to the size of the loaded graphic .AutoSize = True .BorderStyle = 0 .Move 0, 0 .Cls 'obviously, change this to a valid image on your system .Picture = LoadPicture("c:\windows\xp5layout.jpg") End With With HScroll1 .Max = (Picture2.ScaleWidth - Picture1.ScaleWidth) .LargeChange = .Max \ 10 .SmallChange = .Max \ 25 .Enabled = (Picture1.ScaleWidth <= Picture2.ScaleWidth) .ZOrder 0 End With With VScroll1 .Max = (Picture2.ScaleHeight - Picture1.ScaleHeight) .LargeChange = .Max \ 10 .SmallChange = .Max \ 25 .Enabled = (Picture1.ScaleHeight <= Picture2.ScaleHeight) .ZOrder 0 End With Picture3.ZOrder 0 End Sub Private Sub Form_Resize() 'Picture1 is the *outer* pix box (the red viewport) 'Picture2 is the inner pix box (the cyan container to scroll within the viewport) 'don't attempt resizing if minimized! If Me.WindowState <> vbMinimized Then 'this prevents an error if 'the form is sized too small If (Me.ScaleHeight > HScroll1.Height) And _ (Me.ScaleWidth > VScroll1.Width) Then Picture1.Move 0, 0, Me.ScaleWidth - VScroll1.Width, _ Me.ScaleHeight - HScroll1.Height With HScroll1 .Left = 0 .Top = Picture1.Height .Width = Picture1.Width .ZOrder 0 .Enabled = (Picture1.ScaleWidth < Picture2.ScaleWidth) 'if the form has been resized to 'display the entire pixbox, 'disable the scrollbars If .Enabled Then .Max = (Picture2.ScaleWidth - Picture1.ScaleWidth) End If End With With VScroll1 .Left = Picture1.Width .Top = 0 .Height = Picture1.Height .ZOrder 0 .Enabled = (Picture1.ScaleHeight < Picture2.ScaleHeight) If .Enabled Then .Max = (Picture2.ScaleHeight - Picture1.ScaleHeight) End If End With 'position the fake sizing grip Picture3.Move VScroll1.Left, HScroll1.Top End If '(Me.ScaleHeight > HScroll1.Height) And ... End If 'Me.WindowState End Sub Private Sub Form_Unload(Cancel As Integer) Set Form1 = Nothing End Sub Private Sub Picture3_MouseDown(Button As Integer, Shift As Integer, X As Single, Y As Single) 'if a sizable window.. If bWindowIsResizable Then '..fake a resize grabber action If Button = vbLeftButton Then ReleaseCapture SendMessage Me.hwnd, WM_NCLBUTTONDOWN, HTBOTTOMRIGHT, ByVal 0& End If End If End Sub Private Sub Picture3_MouseMove(Button As Integer, Shift As Integer, X As Single, Y As Single) 'if a sizable window.. If bWindowIsResizable Then '..users expect a sizing arrow Picture3.MousePointer = vbSizeNWSE End If End Sub Private Sub VScroll1_Change() Picture2.Top = -VScroll1.Value End Sub Private Sub VScroll1_Scroll() Picture2.Top = -VScroll1.Value End Sub Private Sub HScroll1_Change() Picture2.Left = -HScroll1.Value End Sub Private Sub HScroll1_Scroll() Picture2.Left = -HScroll1.Value End Sub |
||||||||
Comments | ||||||||
|
|
|
|||||
|
|||||
|
|||||
Copyright ©1996-2011 VBnet and Randy Birch. All Rights Reserved. |