- •brief contents
- •about this book
- •The Windows Forms namespace
- •Part 1: Hello Windows Forms
- •Part 2: Basic Windows Forms
- •Part 3: Advanced Windows Forms
- •Who should read this book?
- •Conventions
- •Action
- •Result
- •Source code downloads
- •Author online
- •acknowledgments
- •about .NET
- •Casting the .NET
- •Windows Forms overview
- •about the cover illustration
- •Hello Windows Forms
- •1.1 Programming in C#
- •1.1.1 Namespaces and classes
- •1.1.2 Constructors and methods
- •1.1.3 C# types
- •1.1.4 The entry point
- •1.1.5 The Application class
- •1.1.6 Program execution
- •1.2 Adding controls
- •1.2.1 Shortcuts and fully qualified names
- •1.2.2 Fields and properties
- •1.2.3 The Controls property
- •1.3 Loading files
- •1.3.1 Events
- •1.3.2 The OpenFileDialog class
- •1.3.3 Bitmap images
- •1.4 Resizing forms
- •1.4.1 Desktop layout properties
- •1.4.2 The Anchor property
- •1.4.3 The Dock property
- •1.5 Recap
- •2.1 Programming with Visual Studio .NET
- •2.1.1 Creating a project
- •Action
- •Result
- •2.1.2 Executing a program
- •Action
- •Result
- •2.1.3 Viewing the source code
- •View the code generated by Visual Studio .NET
- •Action
- •Result
- •2.2 Adding controls
- •2.2.1 The AssemblyInfo file
- •Action
- •Results
- •2.2.2 Renaming a form
- •Action
- •Result
- •2.2.3 The Toolbox window
- •Action
- •Result
- •2.3 Loading files
- •2.3.1 Event handlers in Visual Studio .NET
- •Action
- •Result
- •2.3.2 Exception handling
- •Action
- •Result
- •Action
- •Results and Comments
- •2.4 Resizing forms
- •2.4.1 Assign the Anchor property
- •Action
- •Result
- •2.4.2 Assign the MinimumSize property
- •Action
- •Result
- •2.5 Recap
- •Basic Windows Forms
- •Menus
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •3.3 Click events
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •3.5 Context menus
- •Action
- •Result
- •Action
- •Result
- •3.6 Recap
- •Status bars
- •4.1 The Control class
- •4.2 The StatusBar class
- •Action
- •Result
- •Action
- •Result
- •4.3.1 Adding panels to a status bar
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •4.5 Recap
- •Reusable libraries
- •5.1 C# classes and interfaces
- •5.2 Class libraries
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •5.3 Interfaces revisited
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •5.4 Robustness issues
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Common file dialogs
- •Action
- •Results
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •6.3 Paint events
- •Action
- •Result
- •Action
- •Result
- •6.4 Context menus revisited
- •Action
- •Result
- •Action
- •Result
- •6.5 Files and paths
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •6.6 Save file dialogs
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •6.7 Open file dialogs
- •Action
- •Result
- •Action
- •Result
- •6.8 Recap
- •Drawing and scrolling
- •7.1 Form class hierarchy
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •7.4 Panels
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Dialog boxes
- •8.1 Message boxes
- •Action
- •Result
- •Action
- •Result
- •8.1.4 Creating A YesNoCancel dialog
- •Action
- •Result
- •Action
- •Result
- •8.2 The Form.Close method
- •8.2.1 The relationship between Close and Dispose
- •Action
- •Result
- •8.3 Modal dialog boxes
- •Action
- •Result
- •Action
- •Result
- •8.3.2 Preserving caption values
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Basic controls
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •9.1.2 Creating a derived form
- •Action
- •Result
- •9.2 Labels and text boxes
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •9.3.6 Adding AlbumEditDlg to our main form
- •Action
- •Result
- •Action
- •Result
- •9.4 Recap
- •List controls
- •10.1 List boxes
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •10.2 Multiselection list boxes
- •10.2.1 Enabling multiple selection
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •10.3 Combo boxes
- •Action
- •Result
- •Action
- •Result
- •10.4 Combo box edits
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •10.5 Owner-drawn lists
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •More controls
- •Action
- •Result
- •Action
- •Result
- •11.2 Tab pages
- •Action
- •Result
- •Action
- •Result
- •11.3.1 Dates and times
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •11.5 Recap
- •A .NET assortment
- •12.1 Keyboard events
- •Action
- •Result
- •Action
- •Result
- •12.2 Mouse events
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •12.3 Image buttons
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •12.4 Icons
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •12.5 Recap
- •Toolbars and tips
- •13.1 Toolbars
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •13.4.2 Creating tool tips
- •Action
- •Result
- •Action
- •Result
- •Advanced Windows Forms
- •List views
- •14.2 The ListView class
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •14.2.3 Populating a ListView
- •Action
- •Result
- •Action
- •14.3 ListView columns
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •14.6 Recap
- •Tree views
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •15.3 Dynamic tree nodes
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •15.4 Node selection
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •15.5 Fun with tree views
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Multiple document interfaces
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •16.3 Merged menus
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •16.4 MDI children
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •16.5 MDI child window management
- •Action
- •Result
- •Action
- •Result
- •16.6 Recap
- •Data binding
- •17.1 Data grids
- •Action
- •Result
- •Action
- •Result
- •17.2 Data grid customization
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Odds and ends .NET
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •18.2 Timers
- •Action
- •Result
- •Action
- •Result
- •18.3 Drag and drop
- •Action
- •Result
- •Action
- •Result
- •18.4 ActiveX controls
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •18.5 Recap
- •C# primer
- •A.1 C# programs
- •A.1.1 Assemblies
- •A.1.2 Namespaces
- •A.2 Types
- •A.2.1 Classes
- •A.2.2 Structures
- •A.2.3 Interfaces
- •A.2.4 Enumerations
- •A.2.5 Delegates
- •A.3 Language elements
- •A.3.1 Built-in types
- •A.3.2 Operators
- •A.3.3 Keywords
- •A.4 Special features
- •A.4.1 Exceptions
- •A.4.2 Arrays
- •A.4.3 Main
- •A.4.4 Boxing
- •A.4.5 Documentation
- •.NET namespaces
- •B.1 System.Collections
- •B.2 System.ComponentModel
- •B.3 System.Data
- •B.4 System.Drawing
- •B.5 System.Globalization
- •B.6 System.IO
- •B.7 System.Net
- •B.8 System.Reflection
- •B.9 System.Resources
- •B.10 System.Security
- •B.11 System.Threading
- •B.12 System.Web
- •B.13 System.Windows.Forms
- •B.14 System.XML
- •Visual index
- •C.1 Objects
- •C.2 Marshal by reference objects
- •C.3 Components
- •C.4 Common dialogs
- •C.7 Event data
- •C.8 Enumerations
- •For more information
- •bibliography
- •Symbols
- •Index
this we will need more than a single photograph in our application. If we can display one, why not more than one. Let’s display multiple photos. We will call this, of course, a photo album.
To keep this chapter somewhat manageable, we will not muck with our main application window here. We will focus instead on creating a photo album abstraction, and wait until chapter 6 to integrate it into our application. Specifically, we will perform the following tasks in this chapter:
•Create a PhotoAlbum class to represent a collection of photograph files.
•Create a Photograph class to represent a single photograph.
•Compile the PhotoAlbum and Photograph classes into an external library.
Before we write any code for these classes, a short design discussion is in order.
5.1C# CLASSES AND INTERFACES
Within our application, we need to represent the album in a way that facilitates the required actions, such as “add an image,” “move to the next photo,” and so forth. You may immediately think of some sort of array, and this will be our approach. This section will present a short design discussion as a way to introduce some terminology we require and lay the groundwork for writing our code.
Each photo is an image file located somewhere on disk. While a simple list of files could be stored in an array of strings, we should not be too hasty here. Requirements change, as do applications. We may want to add additional features to our photo album later, so it makes sense to encapsulate our album in a class to make this possible. Classes in C# are very similar to classes in the C++ and Java languages. We will create a PhotoAlbum class to represent a single photo album, and provide a set of methods that external users of the class, such as our MyPhotos application, can use to retrieve and modify the contents of the album.
What will our album contain? We already mentioned the idea of array file names. Since we would like to provide quick access to the images, we could also consider an array of Bitmap objects. Not a bad idea, except that a bitmap can be pretty large. A full color image such as a photograph uses 24 bits, or three bytes per pixel: one each for a red, blue, and green color. Do the math and you’ll find that a 640×480 pixel image takes up around 900K in memory, or almost 1 MB. A system with 32 MB of RAM will run out of memory fairly quickly, and even 128 or 256 MB systems will feel the pinch. Of course, virtual memory will allow us to use more than the available physical memory, but the performance will not make our users happy. Instead of bitmaps, we will stick with the file names of our images, and create Bitmap objects as required. To accommodate both types of information, and to extend this definition in the future, we will create a Photograph class to encapsulate the concept of a single photograph. Our album will contain zero or more photographs.
One more feature here: once we build our PhotoAlbum and Photograph classes, they could be useful in other programs that wish to use our concept of a photo
C# CLASSES AND INTERFACES |
127 |
album. For example, a genealogy program for creating family trees might want to link to a photo album of a specific person or family. So we will place our new classes in a library that other programs can reuse. In Windows parlance, such a library is called a Dynamic Link Library, or DLL.
5.1.1INTERFACES
As you might expect, the .NET Framework provides a number of classes that can help us here. These classes implement common data structures such as arrays, stacks, queues, and hash tables. Before the ever-appropriate table summarizing such classes, this is a good place to introduce the idea of an interface.
An interface is an abstraction of an abstraction, and should be familiar to programmers of COM or its UNIX ancestor, the distributed computing environment (DCE). While a class encapsulates a data structure and its operations, an interface encapsulates a type of data structure and its operations. This is very similar to an abstract class, except that an interface does not provide any implementations for its members, it just defines the properties, methods, and events that a class should implement in order to support the interface. In practice, an interface is a good way to encapsulate a common idea for use by a number of possibly unrelated classes, while an abstract class is a good way to encapsulate a common idea for use by a number of related classes.
For example, the .NET ICloneable interface defines a type of class that can be cloned, or copied, from an existing class instance to a new one.1 This concept applies to the Array, Brush, Font, String, and a number of other classes throughout the
.NET Framework. Languages such as C++ provide multiple inheritance for this type of support. In C++, ICloneable could be an abstract class and inherited where needed. In C# and Java, only single inheritance is supported, so this is not possible. Instead, both languages provide interfaces as a way to encapsulate common functionality that can be used by a wide range of classes.
For example, the Brush class supports the ICloneable interface. We used this abstract class in chapter 4 to create an owner-drawn status bar panel. Brush objects can be cloned to create a new copy of an existing Brush. You can create an instance of a Brush, since it is a class, but you cannot create an instance of an ICloneable except as a by-product of an existing class that happens to support this interface.
The .NET Framework provides interfaces for everything from enumerating members of a set to transferring data between applications. Some interfaces related to our current discussion on albums are listed in the following table.
1Generally speaking, cloning in .NET always produces a deep copy of an object, as we saw for the menu classes in chapter 3.
128 |
CHAPTER 5 REUSABLE LIBRARIES |
Interfaces related to data collections
Interface |
Description |
Sample Members |
|
|
|
|
|
|
Interface that supports the creation of |
GetEnumerator method, which returns a |
|
|
an enumerator class for iterating over |
class that supports the IEnumerator |
|
|
the elements in a collection. |
interface. |
|
IEnumerable |
Usage |
|
|
|
Supporting this interface allows the C# |
|
|
|
foreach statement to be used with |
|
|
|
instances of a class or structure. |
|
|
|
|
|
|
|
Interface for stepping through the |
Current property, to retrieve the current |
|
|
elements in a collection. |
element from the collection. |
|
IEnumerator |
|
MoveNext method, which advances to |
|
|
the next element in the collection. |
||
|
|
||
|
|
Reset method, which sets the |
|
|
|
enumerator just before the first element. |
|
|
|
|
|
|
An IEnumerable interface that |
Count property, to retrieve the number |
|
|
provides sizing and synchronization |
of elements in the collection. |
|
|
capabilities. This interface is the basis |
SyncRoot property, to retrieve an object |
|
|
for all collections in the .NET |
||
|
for synchronizing multi-threaded access |
||
ICollection |
Framework. |
||
to the collection. |
|||
|
|
||
|
|
CopyTo method, which copies the |
|
|
|
elements in the collection into an Array |
|
|
|
object. |
|
|
|
|
|
|
An ICollection interface that |
Item property, to support array-style |
|
|
provides indexing of its elements. |
indexing of elements using [brackets], |
|
|
Usage |
much like a [] override in C++. |
|
|
|
||
|
Supporting this interface allows a class |
Add method, which adds a new element |
|
IList |
or structure to be treated as an array. |
to the collection. |
|
|
This permits objects to be used as |
Contains method, which determines if |
|
|
targets of data bound controls, as |
||
|
the collection contains a specific object. |
||
|
discussed in chapter 17. |
||
|
Remove method, to remove the element |
||
|
|
||
|
|
from the collection at a given index value. |
|
|
|
|
5.1.2DATA COLLECTION CLASSES
Looking over the interfaces in the table, the IList interface seems particularly appropriate for the task at hand. This allows elements to be added and removed from the collection, and supports array-style indexing. Some of the data collection classes in the .NET Framework are shown in the following table. Note, in particular, those classes in the table that support the IList interface.
C# CLASSES AND INTERFACES |
129 |
Some .NET classes related to data collections
Class |
Description |
Interfaces supported |
Array |
The base class for all array objects. |
|
This class is abstract. |
ArrayList |
A dynamically-sized array. |
CollectionBase |
An abstract class for creating a |
|
strongly typed collection. |
DataView |
A customized view of a database |
|
table. |
Hashtable |
A collection of values stored based on |
|
a hash code of the value, called a key. |
Queue |
A FIFO queue; a first in, first out |
|
collection of objects. |
SortedList |
A sorted collection of keys and values |
|
accessible by both key and index. |
StringCollection |
A collection of string objects. |
Stack |
A LIFO queue; a last in, first out |
|
collection of objects. |
ICloneable, IList, ICollection, IEnumerable
ICloneable, IList,
ICollection, IEnumerable
IList, ICollection, IEnumerable
IList, ICollection, IEnumerable, and others
ICloneable, ICollection,
IEnumerable, IDictionary, and others
ICloneable, ICollection,
IEnumerable
ICloneable, ICollection,
IEnumerable, IDictionary
IList, ICollection,
IEnumerable
ICloneable, ICollection,
IEnumerable
Since we do not have a database here, the DataView class is not appropriate. If all we wanted was a collection of file names, the StringCollection class would work, but then our PhotoAlbum would not be very extensible. This leaves us with a simple array or the ArrayList or CollectionBase classes. A simple fixed-size array is not appropriate since we would like our album to grow dynamically. So we are left to choose between the ArrayList and CollectionBase classes.
Either class would work here, and both classes can be quite useful. An overview of the ArrayList class is shown in .NET Table 5.1. Deriving our PhotoAlbum class from ArrayList would look like this:
// Deriving PhotoAlbum from ArrayList (not our approach) public class PhotoAlbum : System.Collections.ArrayList
{
// Inherits all properties and methods from ArrayList
}
An advantage of this approach is that we would not need to implement many of the methods, since they would be directly inherited from ArrayList. A disadvantage is that all methods would accept any object, and not just our Photograph objects. If you look at the documentation, you will see that the methods in ArrayList operate on object instances. For example, the PhotoAlbum.Add method would have the following signature:
130 |
CHAPTER 5 REUSABLE LIBRARIES |
// PhotoAlbum.Add when derived from ArrayList
public int Add( object value );
So while this would be a very easy implementation, the methods in our PhotoAlbum class would not be type-safe, and therefore not so robust.
.NET Table 5.1 ArrayList class
The ArrayList class is a collection of indexed objects where the number of objects can change dynamically. This class is part of the System.Collections namespace, and is very similar to the Array class for fixed-length collections of objects. The ArrayList class supports the ICloneable, IEnumerable, ICollection, and IList interfaces.
Public |
Capacity |
Gets or sets the maximum number of objects the list can contain. |
Properties |
Count |
Gets or sets the actual number of objects in the array. |
|
||
|
|
|
|
Add |
Adds an object to the end of the array. |
|
AddRange |
Adds the elements from an ICollection interface to the end of |
|
|
the array. |
|
Clear |
Removes all objects from the array. |
|
Contains |
Determines if an object is in the array. Comparison is done using |
|
|
the Object.Equals method. |
|
CopyTo |
Copies the ArrayList, or a portion of it, into a one-dimensional |
Public |
|
Array object. |
|
|
|
Methods |
IndexOf |
Returns the zero-based index of the first occurrence of the given |
|
||
|
|
object in the array, or –1 if the object is not found. Comparison is |
|
|
done using the Object.Equals method. |
|
Remove |
Removes an object from the array. |
|
RemoveAt |
Removes the object at a given index from the array. |
|
Sort |
Sorts the array, using an IComparable interface to compare |
|
|
objects. |
|
TrimToSize |
Sets the capacity of the array to the actual number of objects in it. |
|
|
|
Let’s instead take a look at the CollectionBase class. An overview of this class is shown in .NET Table 5.2. This class is an abstract class, and requires derived classes to implement the additional methods required to support the appropriate interfaces. This requires a little more work on our part, but creates a nicer interface that works with Photograph objects directly.
Before we create our implementation, note that an alternative implementation would incorporate a private ArrayList object in a class derived directly from System.Object. This alternative would look something like the following:
// PhotoAlbum implementation with private ArrayList (not our approach)
class PhotoAlbum
{
// internal (not inherited) ArrayList
C# CLASSES AND INTERFACES |
131 |
private ArrayList _photoArray;
//Constructor and other wrappers
//Custom Add wrapper
public int Add(Photograph photo)
{
return _photoArray.Add(photo);
}
}
This would work just fine and be similar to our actual implementation derived from CollectionBase. Our implementation is more appropriate than this alternative, since the CollectionBase class is designed for just this purpose, and does in fact provide access to an ArrayList member through a protected property.
.NET Table 5.2 CollectionBase class
The CollectionBase class is an abstract class for creating strongly typed collections. A class is strongly typed if it only allows a specific type or types in its methods, rather than a generic type such as an object. Strongly typed classes allow the compiler to ensure that the proper objects are passed to methods in the class, and can prevent errors that would otherwise occur only at runtime.
The CollectionBase class is part of the System.Collections namespace. It supports the IEnumerable, ICollection, and IList interfaces. A complete list of the public members defined by this class is as follows. Derived classes must implement the additional methods to support the required interfaces.
Public |
Count |
Gets or sets the actual number of objects in the array. |
Properties |
|
|
|
|
|
|
Clear |
Removes all objects from the array. |
Public |
GetEnumerator |
Returns an enumerator that can iterate through the |
|
elements in the collection using the IEnumerator |
|
Methods |
|
|
|
interface. |
|
|
|
|
|
RemoveAt |
Removes the object at a given index from the array. |
|
|
|
|
InnerList |
Gets an ArrayList instance representing the collection |
|
|
instance. This can be used when implementing derived |
Protected |
|
classes to modify the collection. |
|
|
|
Properties |
List |
Gets an IList instance representing the collection |
|
||
|
|
instance. This can be used when implementing derived |
|
|
classes to modify the collection. |
|
|
|
|
OnClear |
Performs additional custom processing before clearing the |
|
|
contents of the collection. This can be used by derived |
Protected |
|
classes to perform any required actions before the |
|
collection is cleared. |
|
Methods |
OnInsert |
Performs additional custom processing before inserting an |
|
||
|
|
element into a collection. A number of other protected |
|
|
methods are provided, with a similar purpose. |
|
|
|
132 |
CHAPTER 5 REUSABLE LIBRARIES |