During Week 12 of 266372 you learned about two applications of iterators. The first example was a template class that allowed users to sort an array on different properties without scrambling the original array. This iterator can be used to sort items in a listbox on different fields, and still allow the user to select an item and edit that item in the original array.
The example here does not set up the edit mechanism, but that would be a simple matter to add. This program creates an array of "Customer." The menu item Show Dialog displays a dialog with the customers listed. This dialog has a HeaderControl (the buttons directly above the listbox). The buttons are members of an array of type THeaderSection. When the user presses the button Name, the list is sorted by name. Pressing the AccountId button causes the customers to be sorted by account id.
In some cases it would not make any difference if the array itself were sorted, but in cases where other items (such as an order) record the customer by its subscript in the array, the array must remain unchanged. The sort iterator traverses the array in the order dictated by the Compare class specified for the sort.
First create a new dialog box . Next complete the following steps to get the dialog seen above.
| 1. Select the THeaderControl from the Win32 tab of the control bar. Align the bar to the top of the new dialog | |
| 2. Select Sections in the object inspector for the THeaderControl. Click on the ellipse (three periods). |
|
| 3. The section editor appears. You may name sections, delete sections and change the order that they appear in here. | |
| The width of each section can be adjusted in Object Inspector. | |
You should initialize the iterator and the listbox in the dialog constructor. The iterator must be initialized in the initialization section of the constructor, because the only constructor for objects in this class is non trivial. It requires the array be passed in to initialize the reference to the array. The customers will initially be display in order of name, so the first part of the constructor sorts the iterator by customer name. The next section creates a string in which each customer is separated by an end of line marker. Finally the Text propert of the ListBox property Items is set to the string.
__fastcall TCustomerDlg::TCustomerDlg(TComponent* AOwner)
: TForm(AOwner), _next(SDIAppForm->getCustomers())
{
RcPointer < Compare< Customer> > nameCompare=new NameCompare;
_next.sort(nameCompare);
String buffer=""; // Create whole list in a string
while(_next)
{
buffer = buffer + _next().getDescription()+ '\n';
// End of line marker in last line separates items in list.
_next++;
}
ListBox1->Items->Text = buffer;
}
The sort will happen when you click on the HeaderControl, so you have to create a handler for the click. Select the Event tab in the Object Inspector for the HeadControl. Double click on the space following this event and the program will create a handler for you. Most of this handler is a copy of the last part of the constructor. The only difference is the choice of the Compare class to use in the sort. The pointer Section (last parameter) has a property Index that indicates which in which section the click occurred. Recall sections are numbered from 0 to the number of sections -1. A simple condition can be used as shown here, or in the case of a larger number of choices, you may want to use an abstract factory. This is left as an exercise for the reader.
void __fastcall TCustomerDlg::HeaderControl1SectionClick(
THeaderControl *HeaderControl, THeaderSection *Section)
{
RcPointer < Compare< Customer> > compare;
if (Section->Index ==0 )
compare=new NameCompare;
else
compare = new IdCompare;
_next.sort(compare);
String buffer="";
while(_next)
{
buffer = buffer + _next().getDescription()+ '\n';
_next++;
}
ListBox1->Items->Text = buffer;
}
Click here to get a copy of the complete project shown here.