Containers

Many controls can contain other controls, grouping them. The Form control is the ultimate container, but it serves a larger purpose than just containing other controls. The form is the center of Windows Forms-based applications, having many unique properties and methods that empower the Form control to fulfill its role. These include properties such as AcceptButton, Modal, and WindowState, and methods such as Activate and Close. Chapter 5 covers the Form control thoroughly.

Some controls exist only to fill the role of container. They have very few properties, and all their methods are either inherited or overridden from the Control class. They cannot receive focus, although they may play a role in the tab order. Their sole mission is to group other controls to a common purpose. That purpose may be ergonomic, e.g., using a container control to put a border around several labels and text boxes used for gathering address information. The purpose may also be directly functional, e.g., grouping several radio buttons so they become mutually exclusive.

The two controls that exist only to be containers are GroupBox and Panel. They are similar in purpose, but have some very different features. In short, the GroupBox displays its Text property as a caption. It cannot scroll. The Panel control, on the other hand, can scroll but does not display its Text property and cannot have a caption.

The class hierarchy shown in Figure 13-1 explains this behavior. The GroupBox class is derived directly from Control, while the Panel control is derived from Control via the ScrollableControl class, thereby gaining the ability to have scrollbars. Neither GroupBox nor Panel are derived from ContainerControl, even though they are containers.

The ContainerControl class is perhaps misnamed. A control does not have to derive from ContainerControl to be a container, but it has to derive from Control (which has a Controls property that returns a collection of contained controls). The ContainerControl class' main purpose is to deal with focus management.

The Panel class has a read/write Text property that overrides the Control.Text property, but it does not display as part of the control.

If either a GroupBox or Panel control's Enabled property is set to false, then all the controls contained within will also be disabled. Likewise, if a GroupBox or Panel control's Visible property is set to false, then none of its child controls will be visible.

Both the GroupBox and Panel controls were demonstrated in Example 11-9 and Example 11-10. Those examples will be reprised here in Example 13-1 (in C#) and Example 13-2 (in VB.NET), with a few minor modifications. The lines of code that differ from the examples in Chapter 11 are highlighted.

When the programs in Example 13-1 and Example 13-2 are compiled and run, they yield the form shown in Figure 13-1. This is similar to that shown in Figure 11-7, except that the panel containing the font style checkboxes is intentionally made short to require a vertical scrollbar, and that panel also has a BorderStyle applied to it.

Figure 13-2. Containers

Example 13-1. Containers in C# (Containers.cs)

using System; using System.Drawing; using System.Windows.Forms; namespace ProgrammingWinApps { public class Containers : Form { Label lbl; Panel pnl; int yDelta; RadioButton rdoAppearanceNormal; RadioButton rdoAppearanceButton; RadioButton rdoCheckAlignMiddleLeft; RadioButton rdoCheckAlignMiddleRight; RadioButton rdoTextAlignMiddleLeft; RadioButton rdoTextAlignMiddleRight; RadioButton rdoTextAlignMiddleCenter; FontStyle[ ] theStyles; public Containers( ) { Text = "Containers"; Size = new Size(350,375); lbl = new Label( ); lbl.Parent = this; lbl.Text = "The quick brown fox..."; lbl.Location = new Point(0,0); lbl.AutoSize = true; lbl.BorderStyle = BorderStyle.Fixed3D; yDelta = lbl.Height + 10; // Get the FontStyles into an array FontStyle theEnum = new FontStyle( ); theStyles = (FontStyle[ ])Enum.GetValues(theEnum.GetType( )); pnl = new Panel( ); pnl.Parent = this; pnl.Location = new Point(0, yDelta ); pnl.Size = new Size(150, (theStyles.Length - 1) * yDelta); pnl.BorderStyle = BorderStyle.Fixed3D; pnl.AutoScroll = true; int i = 1; CheckBox cb; foreach (FontStyle style in theStyles) { cb = new CheckBox( ); pnl.Controls.Add(cb); cb.Location = new Point(25, (yDelta * (i - 1)) + 10); cb.Size = new Size(75,20); cb.Text = style.ToString( ); cb.Tag = style; cb.CheckedChanged += new System.EventHandler(cb_CheckedChanged); if (cb.Text = = "Regular") cb.Checked = true; i++; } GroupBox grpAppearance = new GroupBox( ); grpAppearance.Parent = this; grpAppearance.Text = "Appearance"; grpAppearance.Location = new Point(175,yDelta); grpAppearance.Size = new Size(150, yDelta * 3); rdoAppearanceNormal = new RadioButton( ); rdoAppearanceNormal.Parent = grpAppearance; rdoAppearanceNormal.Text = "Normal"; rdoAppearanceNormal.Location = new Point(10, 15); rdoAppearanceNormal.Checked = true; rdoAppearanceNormal.CheckedChanged += new System.EventHandler(rdoAppearance_CheckedChanged); rdoAppearanceButton = new RadioButton( ); rdoAppearanceButton.Parent = grpAppearance; rdoAppearanceButton.Text = "Button"; rdoAppearanceButton.Location = new Point(10, 15 + yDelta); rdoAppearanceButton.CheckedChanged += new System.EventHandler(rdoAppearance_CheckedChanged); GroupBox grpCheckAlign = new GroupBox( ); grpCheckAlign.Parent = this; grpCheckAlign.Text = "CheckAlign"; grpCheckAlign.Location = new Point(175, grpAppearance.Bottom + 25); grpCheckAlign.Size = new Size(150, yDelta * 3); rdoCheckAlignMiddleLeft = new RadioButton( ); rdoCheckAlignMiddleLeft.Parent = grpCheckAlign; rdoCheckAlignMiddleLeft.Text = "Middle Left"; rdoCheckAlignMiddleLeft.Tag = ContentAlignment.MiddleLeft; rdoCheckAlignMiddleLeft.Location = new Point(10, 15); rdoCheckAlignMiddleLeft.Checked = true; rdoCheckAlignMiddleLeft.CheckedChanged += new System.EventHandler(rdoCheckAlign_CheckedChanged); rdoCheckAlignMiddleRight = new RadioButton( ); rdoCheckAlignMiddleRight.Parent = grpCheckAlign; rdoCheckAlignMiddleRight.Text = "Middle Right"; rdoCheckAlignMiddleRight.Tag = ContentAlignment.MiddleRight; rdoCheckAlignMiddleRight.Location = new Point(10, 15 + yDelta); rdoCheckAlignMiddleRight.CheckedChanged += new System.EventHandler(rdoCheckAlign_CheckedChanged); GroupBox grpTextAlign = new GroupBox( ); grpTextAlign.Parent = this; grpTextAlign.Text = "TextAlign"; grpTextAlign.Location = new Point(175, grpCheckAlign.Bottom + 25); grpTextAlign.Size = new Size(150, yDelta * 4); rdoTextAlignMiddleLeft = new RadioButton( ); rdoTextAlignMiddleLeft.Parent = grpTextAlign; rdoTextAlignMiddleLeft.Text = "Middle Left"; rdoTextAlignMiddleLeft.Tag = ContentAlignment.MiddleLeft; rdoTextAlignMiddleLeft.Location = new Point(10, 15); rdoTextAlignMiddleLeft.Checked = true; rdoTextAlignMiddleLeft.CheckedChanged += new System.EventHandler(rdoTextAlign_CheckedChanged); rdoTextAlignMiddleRight = new RadioButton( ); rdoTextAlignMiddleRight.Parent = grpTextAlign; rdoTextAlignMiddleRight.Text = "Middle Right"; rdoTextAlignMiddleRight.Tag = ContentAlignment.MiddleRight; rdoTextAlignMiddleRight.Location = new Point(10, 15 + yDelta); rdoTextAlignMiddleRight.CheckedChanged += new System.EventHandler(rdoTextAlign_CheckedChanged); rdoTextAlignMiddleCenter = new RadioButton( ); rdoTextAlignMiddleCenter.Parent = grpTextAlign; rdoTextAlignMiddleCenter.Text = "Middle Center"; rdoTextAlignMiddleCenter.Tag = ContentAlignment.MiddleCenter; rdoTextAlignMiddleCenter.Location = new Point(10, 15 + (2 * yDelta)); rdoTextAlignMiddleCenter.CheckedChanged += new System.EventHandler(rdoTextAlign_CheckedChanged); } // close for constructor static void Main( ) { Application.Run(new Containers( )); } private void cb_CheckedChanged(object sender, EventArgs e) { FontStyle fs = 0; for (int i = 0; i < pnl.Controls.Count; i++) { CheckBox cb = (CheckBox)pnl.Controls[i]; if (cb.Checked) fs |= (FontStyle)cb.Tag; } lbl.Font = new Font(lbl.Font, fs); } private void rdoAppearance_CheckedChanged(object sender, EventArgs e) { if (rdoAppearanceNormal.Checked) { for (int i = 0; i < pnl.Controls.Count; i++) { CheckBox cb = (CheckBox)pnl.Controls[i]; cb.Appearance = Appearance.Normal; } } else { for (int i = 0; i < pnl.Controls.Count; i++) { CheckBox cb = (CheckBox)pnl.Controls[i]; cb.Appearance = Appearance.Button; } } } private void rdoCheckAlign_CheckedChanged(object sender, EventArgs e) { RadioButton rdo = (RadioButton)sender; for (int i = 0; i < pnl.Controls.Count; i++) { CheckBox cb = (CheckBox)pnl.Controls[i]; cb.CheckAlign = (ContentAlignment)rdo.Tag; } } private void rdoTextAlign_CheckedChanged(object sender, EventArgs e) { RadioButton rdo = (RadioButton)sender; for (int i = 0; i < pnl.Controls.Count; i++) { CheckBox cb = (CheckBox)pnl.Controls[i]; switch ((int)rdo.Tag) { case (int)ContentAlignment.MiddleLeft : cb.TextAlign = ContentAlignment.MiddleLeft; break; case (int)ContentAlignment.MiddleRight : cb.TextAlign = ContentAlignment.MiddleRight; break; case (int)ContentAlignment.MiddleCenter : cb.TextAlign = ContentAlignment.MiddleCenter; break; } } } // close for rdoTextAlign_CheckedChanged } // close for form class } // close form namespace

Example 13-2. Containers in VB.NET (Containers.vb)

Option Strict On imports System imports System.Drawing imports System.Windows.Forms namespace ProgrammingWinApps public class Containers : inherits Form dim lbl as Label dim pnl as Panel dim yDelta as integer dim rdoAppearanceNormal as RadioButton dim rdoAppearanceButton as RadioButton dim rdoCheckAlignMiddleLeft as RadioButton dim rdoCheckAlignMiddleRight as RadioButton dim rdoTextAlignMiddleLeft as RadioButton dim rdoTextAlignMiddleRight as RadioButton dim rdoTextAlignMiddleCenter as RadioButton dim theStyles as FontStyle( ) public sub New( ) Text = "Containers" Size = new Size(350,375) lbl = new Label( ) lbl.Parent = me lbl.Text = "The quick brown fox..." lbl.Location = new Point(0,0) lbl.AutoSize = true lbl.BorderStyle = BorderStyle.Fixed3D yDelta = lbl.Height + 10 ' get the FontStyle values into an array dim theEnum as new FontStyle( ) theStyles = CType([Enum].GetValues( _ theEnum.GetType( )), FontStyle( )) pnl = new Panel( ) pnl.Parent = me pnl.Location = new Point(0, yDelta ) pnl.Size = new Size(150, (theStyles.Length - 1) * yDelta) pnl.BorderStyle = BorderStyle.Fixed3D pnl.AutoScroll = true dim i as integer = 1 dim style as FontStyle dim cb as CheckBox for each style in theStyles cb = new CheckBox( ) pnl.Controls.Add(cb) cb.Location = new Point(25, (yDelta * (i - 1)) + 10) cb.Size = new Size(75,20) cb.Text = style.ToString( ) cb.Tag = style AddHandler cb.CheckedChanged, AddressOf cb_CheckedChanged if cb.Text = "Regular" then cb.Checked = true end if i = i + 1 next dim grpAppearance as GroupBox = new GroupBox( ) grpAppearance.Parent = me grpAppearance.Text = "Appearance" grpAppearance.Location = new Point(175,yDelta) grpAppearance.Size = new Size(150, yDelta * 3) rdoAppearanceNormal = new RadioButton( ) rdoAppearanceNormal.Parent = grpAppearance rdoAppearanceNormal.Text = "Normal" rdoAppearanceNormal.Location = new Point(10, 15) rdoAppearanceNormal.Checked = true AddHandler rdoAppearanceNormal.CheckedChanged, _ AddressOf rdoAppearance_CheckedChanged rdoAppearanceButton = new RadioButton( ) rdoAppearanceButton.Parent = grpAppearance rdoAppearanceButton.Text = "Button" rdoAppearanceButton.Location = new Point(10, 15 + yDelta) AddHandler rdoAppearanceButton.CheckedChanged, _ AddressOf rdoAppearance_CheckedChanged dim grpCheckAlign as GroupBox = new GroupBox( ) grpCheckAlign.Parent = me grpCheckAlign.Text = "CheckAlign" grpCheckAlign.Location = new Point(175, _ grpAppearance.Bottom + 25) grpCheckAlign.Size = new Size(150, yDelta * 3) rdoCheckAlignMiddleLeft = new RadioButton( ) rdoCheckAlignMiddleLeft.Parent = grpCheckAlign rdoCheckAlignMiddleLeft.Text = "Middle Left" rdoCheckAlignMiddleLeft.Tag = ContentAlignment.MiddleLeft rdoCheckAlignMiddleLeft.Location = new Point(10, 15) rdoCheckAlignMiddleLeft.Checked = true AddHandler rdoCheckAlignMiddleLeft.CheckedChanged, _ AddressOf rdoCheckAlign_CheckedChanged rdoCheckAlignMiddleRight = new RadioButton( ) rdoCheckAlignMiddleRight.Parent = grpCheckAlign rdoCheckAlignMiddleRight.Text = "Middle Right" rdoCheckAlignMiddleRight.Tag = ContentAlignment.MiddleRight rdoCheckAlignMiddleRight.Location = new Point(10, 15 + yDelta) AddHandler rdoCheckAlignMiddleRight.CheckedChanged, _ AddressOf rdoCheckAlign_CheckedChanged dim grpTextAlign as GroupBox = new GroupBox( ) grpTextAlign.Parent = me grpTextAlign.Text = "TextAlign" grpTextAlign.Location = new Point(175, grpCheckAlign.Bottom + 25) grpTextAlign.Size = new Size(150, yDelta * 4) rdoTextAlignMiddleLeft = new RadioButton( ) rdoTextAlignMiddleLeft.Parent = grpTextAlign rdoTextAlignMiddleLeft.Text = "Middle Left" rdoTextAlignMiddleLeft.Tag = ContentAlignment.MiddleLeft rdoTextAlignMiddleLeft.Location = new Point(10, 15) rdoTextAlignMiddleLeft.Checked = true AddHandler rdoTextAlignMiddleLeft.CheckedChanged, _ AddressOf rdoTextAlign_CheckedChanged rdoTextAlignMiddleRight = new RadioButton( ) rdoTextAlignMiddleRight.Parent = grpTextAlign rdoTextAlignMiddleRight.Text = "Middle Right" rdoTextAlignMiddleRight.Tag = ContentAlignment.MiddleRight rdoTextAlignMiddleRight.Location = new Point(10, 15 + yDelta) AddHandler rdoTextAlignMiddleRight.CheckedChanged, _ AddressOf rdoTextAlign_CheckedChanged rdoTextAlignMiddleCenter = new RadioButton( ) rdoTextAlignMiddleCenter.Parent = grpTextAlign rdoTextAlignMiddleCenter.Text = "Middle Center" rdoTextAlignMiddleCenter.Tag = ContentAlignment.MiddleCenter rdoTextAlignMiddleCenter.Location = new Point(10, _ 15 + (2 * yDelta)) AddHandler rdoTextAlignMiddleCenter.CheckedChanged, _ AddressOf rdoTextAlign_CheckedChanged end sub ' close for constructor public shared sub Main( ) Application.Run(new Containers( )) end sub private sub cb_CheckedChanged(ByVal sender as object, _ ByVal e as EventArgs) dim fs as FontStyle = 0 dim i as integer for i = 0 to pnl.Controls.Count - 1 dim cb as CheckBox = CType(pnl.Controls(i), CheckBox) if cb.Checked then fs = fs or CType(cb.Tag, FontStyle) end if next lbl.Font = new Font(lbl.Font, fs) end sub private sub rdoAppearance_CheckedChanged(ByVal sender as object, _ ByVal e as EventArgs) dim i as integer if rdoAppearanceNormal.Checked then for i = 0 to pnl.Controls.Count - 1 dim cb as CheckBox = CType(pnl.Controls(i), CheckBox) cb.Appearance = Appearance.Normal next else for i = 0 to pnl.Controls.Count - 1 dim cb as CheckBox = CType(pnl.Controls(i), CheckBox) cb.Appearance = Appearance.Button next end if end sub private sub rdoCheckAlign_CheckedChanged(ByVal sender as object, _ ByVal e as EventArgs) dim rdo as RadioButton = CType(sender, RadioButton) dim i as integer for i = 0 to pnl.Controls.Count - 1 dim cb as CheckBox = CType(pnl.Controls(i), CheckBox) cb.CheckAlign = CType(rdo.Tag, ContentAlignment) next end sub private sub rdoTextAlign_CheckedChanged(ByVal sender as object, _ ByVal e as EventArgs) dim rdo as RadioButton = CType(sender, RadioButton) dim i as integer for i = 0 to pnl.Controls.Count - 1 dim cb as CheckBox = CType(pnl.Controls(i), CheckBox) select case rdo.Tag case ContentAlignment.MiddleLeft cb.TextAlign = ContentAlignment.MiddleLeft case ContentAlignment.MiddleRight cb.TextAlign = ContentAlignment.MiddleRight case ContentAlignment.MiddleCenter cb.TextAlign = ContentAlignment.MiddleCenter end select next end sub end class end namespace

The Panel control was made too short by modifying the line of code that calculates and sets the Size property. In the version in the previous chapter, the vertical size was based on the Length property of the Styles array plus 1. In the following examples, the vertical size is minus 1. The BorderStyle property is set to Fixed3D, so you can see the outline of the panel, and the AutoScale property is set to true:

pnl.Size = new Size(150, (theStyles.Length - 1) * yDelta); pnl.BorderStyle = BorderStyle.Fixed3D; pnl.AutoScroll = true;

pnl.Size = new Size(150, (theStyles.Length - 1) * yDelta) pnl.BorderStyle = BorderStyle.Fixed3D pnl.AutoScroll = true

By setting the AutoScale property to true, either or both a vertical and horizontal scrollbar will appear, if necessary. In this example, only the vertical scrollbar was necessary.

The other change made in these examples is inside the iteration that generates the CheckBox controls in the panel. The versions of the programs in Chapter 11 added each checkbox to the panel with the following line of code:

cb.Parent = pnl

These examples use the Add method to add each checkbox to the Controls collection of the Panel control.

pnl.Controls.Add(cb)

The result is the same either way.

There is no need to repeat how radio buttons and checkboxes work. Note, however, that the group box control makes each set of radio buttons independent and mutually exclusive within its set.

Категории