During its lifetime, the form is likely to take up space at some location. The initial location for the form is governed by the StartPosition property, which can have one of several values from the FormStartPosition enumeration: Enum FormStartPosition CenterParent CenterScreen Manual WindowsDefaultBounds WindowsDefaultLocation 'Form.StartPosition default value End Enum These values have the following behavior:
The size and location of the form are exposed via the Size and Location properties, of type Size and Point, respectively (both from the System.Drawing namespace). As a shortcut, the properties of the size of a form are exposed directly via the Height and Width form properties, and those of the location are exposed via the Left, Right, Top, and Bottom properties. Figure 2.3 shows the basic size and location properties on a form. Figure 2.3. The DesktopLocation, Location, ClientSize, and Size Properties (See Plate 4)
When the upper-left corner of a form changes, that's a move , which can be handled in the Move or LocationChanged event handler. When the width or height of a form changes, that's a resize , which can be handled in the Resize or SizeChanged event handler. [6] Sometimes one gesture of the mouse can cause all move and size events to happen. For example, resizing a form by dragging the top-left corner would change the location and the size of the form.
The location of the form is in absolute screen coordinates. If you're interested in the location of the form relative to the desktop ”so that, for example, your form's caption never appears underneath the shell's taskbar ”then even if it's on the top edge, as shown in Figure 2.3, you can use the DesktopLocation property. Here's an example: Sub Form3_Load(sender As Object, e As System.EventArgs) _ Handles MyBase.Load Me.Location = New Point(1, 1) ' Could end up under the shell's taskbar Me.DesktopLocation = New Point(1, 1) ' Will always be in the desktop Me.SetDesktopLocation(1, 1) ' A simpler form of the preceding line End Sub Locations are expressed via the Point structure from the System.Drawing namespace, the interesting parts of which are shown here: Structure Point ' Fields Public Shared ReadOnly Empty As Point ' Constructors Public Sub New(ByVal x As Integer, ByVal y As Integer) ' Properties Public ReadOnly Property IsEmpty() As Boolean Public Property X() As Integer Public Property Y() As Integer ' Methods Public Shared Function Ceiling(ByVal value As PointF) As Point Public Sub Offset(ByVal dx As Integer, ByVal dy As Integer) Public Shared Function Round(ByVal values As PointF) As Point Public Overrides Function ToString() As String Public Shared Function Truncate(ByVal value As PointF) As Point End Structure The PointF structure is very similar to the Point structure, but PointF is used in drawing applications when more precise floating point measurements are required. Sometimes you'll need to convert from a Point to a PointF object to be able to call some methods or set some properties. You can do so without any extra effort: ' Can convert directly from Point to PointF Dim pt1 As Point = New Point(10,20) Dim pt2 As PointF = pt1 ' Yields PointF(10.0, 20.0) However, because floating point numbers contain extra precision that will be lost in the conversion, you'll need to be explicit about how to convert from a PointF to a Point object using the static Truncate, Round, and Ceiling methods of the Point class: ' Need to be explicit when converting from a PointF to a Point Dim pt1 As PointF = New PointF(1.2, 1.8) Dim pt2 As Point = Point.Truncate(pt1) ' Yields Point(1,1) Dim pt3 As Point = Point.Round(pt1) ' Yields Point(1,2) Dim pt4 As Point = Point.Ceiling(pt1) ' Yields Point(2,2) The size of a window is reflected in the Size property, also from System.Drawing (Size also has a SizeF counterpart and provides the same capabilities for conversion): Structure Size ' Fields Public Shared ReadOnly Empty As Size ' Constructors Public Sub New ( ByVal width As Integer , ByVal height As Integer ) ' Properties Public Property Height() As Boolean Public ReadOnly Property IsEmpty() As Boolean Public Property width() As Integer ' Methods Public Shared Function Ceiling( ByVal value As SizeF) As Size Public Overloads Overrides Function Equals( ByVal obj As Object ) _ As Boolean Public Shared Function Round( ByVal value As SizeF) As Size Public Overrides Function ToString() As String Public Shared Function Truncate( ByVal value As SizeF) As Size End Structure Although the Size property represents the size of the entire window, a form isn't responsible for rendering all of its contents. The form can have edges, a caption, and scrollbars, all of which are drawn by Windows. The part that the form is responsible for is the ClientSize, as shown in Figure 2.3. It's useful to save the ClientSize property between application sessions because it's independent of the current adornment settings the user has established. Similarly, resizing the form to make sure there's enough space to render your form's state is often related to the client area of the form and not to the size of the form as a whole: Sub Form2_Load(sender As System.Object, e As System.EventArgs) _ Handles MyBase.Load Me.ClientSize = New Size(100, 100) ' Set the client area explicitly Me.SetClientSizeCore(100, 100) ' Use a helper function from the base End Sub A Rectangle combines a Point and a Size and also has a RectangleF counterpart. The Bounds property gives a rectangle of the form relative to the screen, whereas the DesktopBounds property is a rectangle relative to the desktop for top-level windows (and not for child windows). The ClientRectangle property is a rectangle relative to the form itself, describing the client area of the form. Of the three, ClientRectangle tends to be the most used, if for no other reason than to describe which area to use when drawing: Sub Form1_Paint(ByVal sender As Object, _ ByVal e As System.Windows.Forms.PaintEventArgs) _ Handles MyBase.Paint Dim g As Graphics = e.Graphics g.FillEllipse(Brushes.Yellow, Me.ClientRectangle) g.DrawEllipse(Pens.DarkBlue, Me.ClientRectangle) End Sub Also, it's sometimes necessary to convert a point that's relative to the screen to one that's relative to the client or vice versa. For example, the HelpRequest event, generated when the user clicks on the Help button and then clicks on a control, is sent to the handler in screen coordinates. However, to determine which control was clicked on requires the mouse position in client coordinates. You can convert between the two coordinate systems by using PointToScreen and PointToClient: Sub LoanApplicationDialog_HelpRequested(sender As Object, _ hlpevent As System.Windows.Forms.HelpEventArgs) _ Handles MyBase.HelpRequested ' Convert screen coordinates to client coordinates Dim pt As Point = Me.PointToClient(hlpevent.MousePos) Dim control As Control Dim controlNeedingHelp As Control For Each control In Me.Controls If control.Bounds.Contains(pt) Then controlNeedingHelp = control ... Return End If Next End Sub To translate an entire rectangle between screen and client coordinates, you can also use RectangleToScreen and RectangleToClient. Restricting Form SizeOften our careful control layouts or rendering requirements dictate a certain minimum amount of space. Less often, our forms can't be made to take advantage of more than a certain amount of space (although anchoring and docking, described later, should help with that). Either way, it's possible to set a form's minimum or maximum size via the MinimumSize and MaximumSize properties, respectively. The following example sets a fixed height of 200, a minimum width of 300, and a maximum width so large as to be unlimited: Sub Form2_Load(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles MyBase.Load ' min width is 300, min height is 200 Me.MinimumSize = New Size(300, 200) ' max width is unlimited, max height is 200 Me.MaximumSize = New Size(Integer.MaxValue, 200) End Sub Notice that the code uses the maximum value of an integer to specify that there is no effective maximum width on the form. You may be tempted to use zero for this value instead, but if either the Width or the Height property of the Size used to set the minimum or maximum is nonzero, then both values are used. This would set the maximum size of your form to zero instead of "no maximum." One other setting that governs a form's size and location is WindowState, which can be one of the values from the FormWindowState enumeration: Enum FormWindowState Maximized Minimized Normal 'Form.WindowState default value End Enum By default, the WindowState is set to Normal, which means that it's not maximized to take up the entire desktop, nor is it minimized so that none of the form shows at all and only a button is shown in the taskbar. Your program can get or set this property at will to manage the state of your form. However, if you're saving the size and location of your form between application sessions, you may decide to reset the WindowState to Normal so that the size being saved represents the size in the normal state and not the minimized or maximized state: Sub Form2_Closing(sender As Object, e As CancelEventArgs) _ Handles MyBase.Closing Dim state As FormWindowState = Me.WindowState Me.WindowState = System.Windows.Forms.FormWindowState.Normal Dim location As Point = Me.Location Dim size As Size = Me.ClientSize ' ... save state, location and size properties between sessions ... ' ... restore properties in Load event ... End Sub For a description of how and where to keep application settings between sessions, read Chapter 11: Applications and Settings. Z-OrderAnother location property that you may let your users influence or keep between sessions is the TopLevel property. So far I've discussed location in terms of x and y. However, as the user switches between windows, Windows also juggles the z-order , which dictates which windows are drawn on top of one another. Furthermore, z-order is split into two tiers. Normal windows are drawn lowest z-order to highest, front to back. Above all the normal windows are the topmost windows, which are also drawn relative to each other, lowest z-order to highest, but no matter the z-order, are always drawn on top of any normal window. For an example of a topmost window, pressing Ctrl+Shift+ESC under many versions of Windows will bring up Task Manager. By default, it's a topmost window and always draws on top of normal windows, whether or not it is the active window. You can change this behavior (I always do) by unchecking the Options Always On Top setting. If Task Manager were implemented using WinForms, it would implement this feature by toggling the TopMost property on its main form. |