|
|
Title | Size Forms to Fit the Screen |
Keywords | sizing, resizing, forms, fit screen |
Categories | Tips and Tricks, Tutorials |
|
|
Size Forms to Fit the Screen
This tutorial describes several ways a program can handle different screen resolutions.
Suppose you carefully craft a form sized to fit your screen. You position every control exactly to achieve the perfect visual effect. Then you distribute the program and your customers run it on a screen with 640 x 480 pixels. You designed it with 800 x 600 pixels so the form doesn't fit.
Modern computers can work at many different resolutions depending on how many colors they display. My computer can run at these resolutions:
640 x 480 |
720 x 480 |
720 x 576 |
800 x 600 |
1024 x 768 |
1152 x 854 |
1280 x 1024 |
1600 x 1200 |
So what can you do to ensure that a form will look good at all resolutions? Here are some approaches you can take:
Design your form for the smallest screen the users will have, probably 640 x 480 pixels. When the screen is larger, you can center it, taking the task bar into account like this:
|
|
Private Type RECT
Left As Long
Top As Long
Right As Long
Bottom As Long
End Type
Private Declare Function SystemParametersInfo Lib "user32" _
Alias "SystemParametersInfoA" (ByVal uAction As Long, _
ByVal uParam As Long, ByRef lpvParam As RECT, _
ByVal fuWinIni As Long) As Long
Private Const SPI_GETWORKAREA = 48
' Center the form taking the task bar
' into account.
Private Sub CenterForm(ByVal frm As Form)
Dim wa_info As RECT
Dim wa_wid As Single
Dim wa_hgt As Single
If SystemParametersInfo(SPI_GETWORKAREA, _
0, wa_info, 0) <> 0 _
Then
' We got the work area bounds.
' Center the form in the work area.
wa_wid = ScaleX(wa_info.Right, vbPixels, vbTwips)
wa_hgt = ScaleY(wa_info.Bottom, vbPixels, vbTwips)
Else
' We did not get the work area bounds.
' Center the form on the whole screen.
wa_wid = Screen.Width
wa_hgt = Screen.Height
End If
' Center the form.
frm.Move (wa_wid - Width) / 2, _
(wa_hgt - Height) / 2
End Sub
Private Sub Form_Load()
CenterForm Me
End Sub
|
|
This technique is simple. You only need to design the form once. It requires no special changes or rearrangement of controls at run time.
The disadvantage of this technique is that it does not take full advantage of the screen if it has a greater resolution than 640 x 480. If the screen is 800 x 600, you could display a lot more data.
This method also leaves some of the screen uncovered. That generally does not change the program's usability, but it can be distracting. Fortunately it's easy to cover the entire screen. Simply maximize the form by setting the WindowState property to vbMaximized. Then center the form's controls in the form. This is easiest if you place the controls inside a PictureBox. Then you only need to center the PictureBox.
|
|
' At design time we set:
' ControlBox = False
' Caption = ""
' WindowState = Maximized
' BorderStyle = FixedSingle
Private Sub Form_Resize()
picCenter.BorderStyle = vbBSNone
picCenter.Move _
(ScaleWidth - picCenter.Width) / 2, _
(ScaleHeight - picCenter.Height) / 2
End Sub
|
|
If you like, you can add a picture or pattern to the form so the background is not completely blank.
When you design for different resolutions, remember that color resolution and pixel resolution are related. On my computer, I can display 24-bit color at up to 1280 x 1024 pixels. If I go to 1660 x 1200 pixels, however, the system only has enough graphic memory to display 8-bit color (256 colors).
If you expect users to set their screens to use very high spatial resolution, you should also expect them to be using low color resolution. If your application displays photographic images or uses lots of colors, some of the colors may be lost. Your program may become unusable at these higher spatial resolutions. In that case, you may want to simply tell the user not to use higher spatial resolutions and you won't have to worry about them.
Probably the most popular solution to the form sizing dilemma is to resize the form's controls automatically so they fill the form.
When the program starts, the Form_Load event handler calls subroutine SaveSizes. This routine saves each control's size and position in an array of the ControlPositionType user-defined type (UDT). Notice how the code handles Line controls specially because they have X1, Y1, X2, and Y2 properties instead of the usual Left, Top, Width, and Height properties.
When the form is resized, the Form_Resize event handler calls subroutine ResizeControls. This routine loops through each of the controls scaling their size and position properties appropriately for the form's new size.
|
|
Private Type ControlPositionType
Left As Single
Top As Single
Width As Single
Height As Single
FontSize As Single
End Type
Private m_ControlPositions() As ControlPositionType
Private m_FormWid As Single
Private m_FormHgt As Single
' Save the form's and controls' dimensions.
Private Sub SaveSizes()
Dim i As Integer
Dim ctl As Control
' Save the controls' positions and sizes.
ReDim m_ControlPositions(1 To Controls.Count)
i = 1
For Each ctl In Controls
With m_ControlPositions(i)
If TypeOf ctl Is Line Then
.Left = ctl.X1
.Top = ctl.Y1
.Width = ctl.X2 - ctl.X1
.Height = ctl.Y2 - ctl.Y1
Else
.Left = ctl.Left
.Top = ctl.Top
.Width = ctl.Width
.Height = ctl.Height
On Error Resume Next
.FontSize = ctl.Font.Size
On Error GoTo 0
End If
End With
i = i + 1
Next ctl
' Save the form's size.
m_FormWid = ScaleWidth
m_FormHgt = ScaleHeight
End Sub
' Arrange the controls for the new size.
Private Sub ResizeControls()
Dim i As Integer
Dim ctl As Control
Dim x_scale As Single
Dim y_scale As Single
' Don't bother if we are minimized.
If WindowState = vbMinimized Then Exit Sub
' Get the form's current scale factors.
x_scale = ScaleWidth / m_FormWid
y_scale = ScaleHeight / m_FormHgt
' Position the controls.
i = 1
For Each ctl In Controls
With m_ControlPositions(i)
If TypeOf ctl Is Line Then
ctl.X1 = x_scale * .Left
ctl.Y1 = y_scale * .Top
ctl.X2 = ctl.X1 + x_scale * .Width
ctl.Y2 = ctl.Y1 + y_scale * .Height
Else
ctl.Left = x_scale * .Left
ctl.Top = y_scale * .Top
ctl.Width = x_scale * .Width
If Not (TypeOf ctl Is ComboBox) Then
' Cannot change height of ComboBoxes.
ctl.Height = y_scale * .Height
End If
On Error Resume Next
ctl.Font.Size = y_scale * .FontSize
On Error GoTo 0
End If
End With
i = i + 1
Next ctl
End Sub
|
|
Note that this example does not scale controls within other controls. For example, if you place a TextBox inside a PictureBox, the TextBox's position and dimensions are relative to the PictureBox not the form. This example does not handle this case.
This example also does not stretch pictures.
For a more complete example, see the Stretchable control in my book Custom Controls Library.
This technique fills the form with controls but it doesn't give the user any new information it just makes things bigger. That's okay if you are only increasing the form size slightly, perhaps from a screen size of 640 x 480 to one of 720 x 480, but it looks a bit silly if you go from a 640 x 480 screen to 1600 x 1200 pixels. In the later case, the result looks sort of like it was drawn in crayon. The following technique provides the best result.
The best method for resizing a form is to make certain scrollable controls resize to fill the extra space. For example, a ListBox or Grid can grow to use the available area and give the user access to new information.
Unfortunately this kind of application is hardest to program because you need to decide yourself which controls can give the user more information by expanding.
In the Form_Resize event handler, resize specific controls that contain scrollable areas to take best advantage of the form's new size. For example, a ListBox, Grid, or TreeView control may be able to display more information when the form is enlarged.
Note that you do not need to arrange the controls if the form is minimized because the user cannot see the controls. Note also that the code should never try to give a control a width or height that is less than zero. I usually set minimum sizes at 120 twips.
|
|
' Make the controls fit.
Private Sub Form_Resize()
Const MARGIN As Single = 120
Dim wid As Single
Dim hgt As Single
' Don't bother if we're minimized.
If WindowState = vbMinimized Then Exit Sub
' See how wide we can make the name and address fields.
wid = ScaleWidth - MARGIN - txtName.Left
If wid < 120 Then wid = 120
txtName.Width = wid
txtStreet.Width = wid
txtCity.Width = wid
' See how big we can make the assignments list.
wid = ScaleWidth - 2 * MARGIN
If wid < 120 Then wid = 120
hgt = ScaleHeight - MARGIN - lstAssignments.Top
If hgt < 120 Then hgt = 120
lstAssignments.Move _
lstAssignments.Left, lstAssignments.Top, _
wid, hgt
End Sub
|
|
For information on controls that automatically resize to fit the form, controls (such as scrolled and paned windows aka splitters) that can help with limited screen space, and for controls that can help in arranging specific controls, see my book Custom Controls Library.
The following Download button includes all three of the previous Zip files.
|
|
|
|
|