Controls: List Boxes

 

Inheritance

TObject
TPersistent
TComponent
TControl
TWinControl
TCustomListBox

A List Box is created using the TListBox

Creating a List Box Control

A list box is immediately derived from the TCustomListBox class and that is where its properties are set. There are three main ways you add a list box to your form.

To create a list box, click the List Box control from the Standard tab of the Component Palette and click on the form. Once the list box is positioned on a container, you can move it by clicking and dragging the control. You can also resize it using any of the techniques we learned to add, position, move, and resize controls on a component. If the list will cover many items, design it so its height can display 8 items at a time; otherwise, for a list of 8 or less items, use only the necessary height that would accommodate all of the items.

ListBox Properties

The most fundamental and the most obvious aspect of a list box is the list of items it displays. The list of items of this control is a TStrings object. If you know the list of items for the control, there are two easy ways you can create it. To create the list at design time, on the Object Inspector, click the Items property name to reveal its ellipsis button on the right field . To create the list, click this button to call the String List Editor, type each item desired, on its own line by pressing Enter.

After creating the list, click OK. To test the control, you can press F9.

To programmatically add the items to a list box, use the TStrings::Add() method. If the list were empty, the new items would be added to the list. If the list already contained one or more items, the new items would be added, by default, to the end of the existing one(s). Here is an example of creating a list of items or adding new ones to a list:

//---------------------------------------------------------------------------
void __fastcall TForm1::FormCreate(TObject *Sender)
{
    ListBox1->Items->Add("Chad");
    ListBox1->Items->Add("Equatorial Guinea");
    ListBox1->Items->Add("Egypt");
    ListBox1->Items->Add("Madagascar");
}
//---------------------------------------------------------------------------

As mentioned already, the user mostly interacts with a list box by selecting an item. At any time you can find out whether an particular item has been selected. This is done using the TCustomListBox::Selected Boolean property.

When the Items of a list box appear in alphabetical order, the list is said to be sorted. By default, the items of a list box are not sorted. To arrange the list to ascending order, set the Sorted property’s value to true. As a Boolean data type, you can set the sorting feature programmatically as follows:

//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
    ListBox1->Sorted = True;
}
//---------------------------------------------------------------------------

If you create an unsorted list, then at one time get it sorted (for example, you can give the user the ability to sort the list, by clicking a button), the list would be sorted. If an item is added to the sorted list, the compiler would automatically insert to the right position following the order. If at another time you allow the user to “unsort” the list, the list would keep its current order. If another item is added when the list is not sorted, the item would be positioned at the end of the list. If you want the list to have its original state, you would have to reset it through code.

If you change the Color property of the ListBox control, its whole background would appear with that color. If you want each item to have its own color, you would have to change the style of the list and properly configure it.

When you create a list of items, they appear in one range of columns. If the number of items exceeds the height, a scrollbar would appear on the control. One alternative you can use is to span the list on more than one column. This is set using the Columns property. By default, the Columns value is set to 0, which means the items appear in one column.

If you position the control on a form whose DockSite property is set to true with the the control has a DragKind property dkDock and the DragMode property set to dmAutomatic, the user will be able to move the control and position it anywhere inside the form.

By default, the user can select only one item in the list. This is controlled by both the ExtendedSelect and the MultiSelect properties. If you want the user to be able to select more than one item, you should set the MultiSelect property to true sinc the ExtendedSelect property would already be set to true. After the user has selected more than one item, you can use the TCustomList::SelCount to find out the number of items that the user would have selected.

The list boxes are designed in three types of style. The default is the lbStandard in which case each item in the list is an AnsiString object. On the other hand, if you want each item of the list to display a graphic or a color, you must set the style to an owner draw. The lbOwnerDrawFixed allows you to set a desired height by each item of the list. This height is controlled through the ItemHeight property. You can set a different height for each item if your set the list style to lbOwnerDrawVariable.

The ItemIndex is a property that identifies which item is selected in a list box. This is a property of highly particular interest. If you try performing an operation thatn requires that an item be selected and no item is selected, the program would throw an error (it would crash). The items in a list box are counted from 0, then 1, etc. The first item, at position 0, can be identified as ListBox1->ItemIndex = 0. If no item is selected in the list, the TCustomListBox::ItemIndex has a value of –1;

ListBox Methods

The only methods a list box control has on its own are its constructor and its destructor. The TListBox is typically used to dynamically create a list box. To create a list box inside of an event or a function, use the new operator. To do this, declare a pointer to a TListBox class. When declaring this object, the constructor of the TListBox needs to know the component that owns the control; this is usually the host or container of the list box. If the ListBox will be placed on a form called Form1, you can create the list box as follows:

//---------------------------------------------------------------------------
void __fastcall TForm1::CreateTheList()
{
    TListBox* Liste = new TListBox(this);
    Liste->Parent = Form1;
}
//---------------------------------------------------------------------------

If the list box will be positioned on another type of container, such as a panel called Panel1, you can create it as follows:

//---------------------------------------------------------------------------
void __fastcall TForm1::CreateTheList()
{
    TListBox* Liste = new TListBox(this);
    Liste->Parent = Panel1;
}
//---------------------------------------------------------------------------

If you create the list box in a function, a method, or an event, the list will exist only inside of that function: you cannot manipulate it from another function, method, or event. If you want the control to be accessed by many functions declare a TListBox object in the header file of the form where the control will be hosted.. Here is an example:

//---------------------------------------------------------------------------
#ifndef Unit1H
#define Unit1H
//---------------------------------------------------------------------------
#include <Classes.hpp>
#include <Controls.hpp>
#include <StdCtrls.hpp>
#include <Forms.hpp>
//---------------------------------------------------------------------------
class TForm1 : public TForm
{
__published:	// IDE-managed Components
private:	// User declarations
    TListBox *Listing;
public:		// User declarations
    __fastcall TForm1(TComponent* Owner);
};
//---------------------------------------------------------------------------
extern PACKAGE TForm1 *Form1;
//---------------------------------------------------------------------------
#endif

After declaring the control, you should initialize it in the form’s contructor. This allows you to specify the contrainer that will host the control:

//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
    : TForm(Owner)
{
    Listing = new TListBox(Form1);
    Listing->Parent = Form1;
    Listing->Left = 120;
    Listing->Top = 80;
}
//---------------------------------------------------------------------------


When an application terminates, Borland C++ Builder takes care of destroying all of the objects that are part of the application. If the objects were created at design time, they are owned by the form. Since the form is owned by the application, the application would destroy the form including its hosted controls. If a control was placed on another container such as a panel, the panel is owned by the form and the form by the application. The destruction would still be smooth when the application executes. If you dynamically create a control, you must specify the owner of the control; otherwise the program would not compile. Since you will have specified the owner or container of the control, when the application exits, the compiler would destroy the form and its control, which would include the control you dynamically created. Therefore, you do not have to worry about the state of the dynamic controls when your application exits. This does not mean that your application would never produce a memory leak, but it would be highly unlikely.

If you want to explicitly destroy your dynamically created object, use its destructor. The best place to destroy a global object is to use the delete operator on the OnDestroy event of the form:

//---------------------------------------------------------------------------
void __fastcall TForm1::FormDestroy(TObject *Sender)
{
    delete Listing;
    Listing = NULL;
}
//---------------------------------------------------------------------------

If the list box was dynamically created inside of a function, you cannot access it outside of that function. If it were declared in the header file, you can use any appropriate method, event, or function to fill the list or to manipulate the control. For example, you can fill out the Listing control we declared earlier as follows:

//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
    Listing->Items->Add("C++ Builder");
    Listing->Items->Add("Delphi");
    Listing->Items->Add("JBuilder");
    Listing->Items->Add("Kylix");
}
//---------------------------------------------------------------------------

Since the items of a list box are derived from the TStrings class, you can use this class’ methods to perform the desired operations on the control. The strings in a list box are counted starting at 0, then 1, and so on.

To add an item at the end of the list, you can write code such as:

//---------------------------------------------------------------------------
void __fastcall TForm1::btnAddLesothoClick(TObject *Sender)
{
    lstCountries->Items->Add("Lesotho");
}
//---------------------------------------------------------------------------

To insert an item in the 2nd position you can write code such as:

//---------------------------------------------------------------------------
void __fastcall TForm1::btnAddSecondClick(TObject *Sender)
{
    lstCountries->Items->Insert(1, "Mauritania");
}
//---------------------------------------------------------------------------

To delete the 4th item of the list, you could write:

//---------------------------------------------------------------------------
void __fastcall TForm1::btnDelete4Click(TObject *Sender)
{
    lstCountries->Items->Delete(3);
}
//---------------------------------------------------------------------------

If you have an Edit control called edtCountry, you can let the user add its content to the list box by double-clicking the edit box. The code could look as follows:

//---------------------------------------------------------------------------
void __fastcall TForm1::Edit1DblClick(TObject *Sender)
{
    lstCountries->Items->Add(edtCountry->Text);
}
//---------------------------------------------------------------------------

If the user is filling out a list box while typing additional items in an Edit control, the best and fastest way to add a new item is when the user presses Enter after typing the item. To implement this behavior, you should find out what key the user pressed. If the user presses Enter when the edit box has focus, you should make sure the edit box contains a string. The code could appear like this:

//---------------------------------------------------------------------------
void __fastcall TForm1::Edit1KeyPress(TObject *Sender, char &Key)
{
    if( Key == 13 ) // If the user presses the Enter key
    {
        if(Edit1->Text != "") // If Edit1 contains something
        {
            // Add the content of Edit1 to ListBox1
            lstCountries->Items->Add(Edit1->Text);
            // Reset Edit1 and make it empty
            Edit1->Text = "";
        }
        else         // Since Edit1 is empty, display a message
            Panel1->Caption = "There is nothing to add";
    }
}
//---------------------------------------------------------------------------

The TCustomListBox::Clear() method is used to clear the control of its whole content:

//---------------------------------------------------------------------------
void __fastcall TForm1::Button2Click(TObject *Sender)
{
    lstCountries->Clear();
}
//---------------------------------------------------------------------------

Operations on List Boxes

The most regular operation users perform on a list box is to select items. This selection is performed by the user clicking one of the items. Using code, you can also select an item in the list. To select the 6th item of the list, you could write the code as:

//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
    lstCountries->ItemIndex = 5;
}
//---------------------------------------------------------------------------

When performing your operations, sometimes you will want to find out if a particular item is selected. You can do this using the ordinal position of the item. For example, to find out if the 3rd item is selected, you can write:

//---------------------------------------------------------------------------
void __fastcall TForm1::Button7Click(TObject *Sender)
{
    if( lstCountries->ItemIndex == 2)
        Panel1->Caption = "The third item is selected";
}
//---------------------------------------------------------------------------

If an item is selected, you can allow the user to perform an operation on it. If a string (that is, any string) is not selected, most operations would fail and the program would crash. Therefore, usually you should make sure an item is selected. An item is selected when the value of the TCustomListBox::ItemIndex is not –1. Operations include:

  1. displaying the selected item of the list box to an edit box:
     
    //---------------------------------------------------------------------------
    void __fastcall TForm1::Button6Click(TObject *Sender)
    {
        // First find out whether an item is selected
        if(lstCountries->ItemIndex != -1) // Put the selected item in the edit
            Edit1->Text = lstCountries->Items->Strings[lstCountries->ItemIndex];
    }
    //---------------------------------------------------------------------------
  2. inserting a new string above the selected item:
     
    //---------------------------------------------------------------------------
    void __fastcall TForm1::Button6Click(TObject *Sender)
    {
        lstCountries->Items->Insert(lstCountries->ItemIndex, Edit1->Text);
    }
    //---------------------------------------------------------------------------
  3. or under the selected string:
     
    //---------------------------------------------------------------------------
    void __fastcall TForm1::Button6Click(TObject *Sender)
    {
        lstCountries->Items->Insert(lstCountries->ItemIndex + 1, Edit1->Text);
    }
    //---------------------------------------------------------------------------

Many times during your design, you will allow users to add or delete items to or from a list box. One way you will do this is to create a list of items originating from another list; this allows you to control the items the user can select from a list before continuing with the issue at hand. Borland C++ Builder ships with a dialog box completely configured to handle this transaction.

To allow two list boxes to exchange data, you provide the appropriate buttons. If only one list will be used as the source, provide one button that could allow the user to select an item. It is also a good idea to allow the user to select and add all items at once. Also important is the ability for the user to remove mistakenly selected items. Over all, these kinds of list boxes handle their transactions through the use of four buttons: two are used to exchange one item at a time from one list to another, two to exchange all items from one list to another.

 


Copyright © 2003-2007 FunctionX, Inc.