Ask the Delphi Pro 10-Minute Solutions

Performing Incremental Searches with a TListbox
By Brendan Delumpa

How can I create a form that has a list box that I can perform an incremental search on?

There are a couple of ways to do incremental searching with list boxes. One way is hard and slow and involves going through the list item by item--the other approach is easy and fast. We are going to take the easy and fast option. For those of you who aren't familiar with incremental searching with list boxes, the concept is simple: A user types part of a string into an edit box, then the list box automatically selects one of its items that most closely matches the value typed by the user. For example, open up any topic search dialog in a Windows Help file. If you type into the edit box, the list will scroll to the value that most closely matches what you type.

Why is having this kind of capability useful? Because it's tedious to scroll through a list that has lots of items. Imagine if a list contained hundreds of unsorted items. Getting to the value you're looking for would take a long time if you only had the capability of scrolling through the list using the vertical scroll bar. But if you knew at least part of the value you're trying to find, entering it into an edit box and getting the item you want immediately is a much more attractive solution.

Let's delve into what you have to do make this solution work. First, here's the unit code for a sample form I produced:


unit uinclist;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  StdCtrls;

type
  TForm1 = class(TForm)
    ListBox1: TListBox;
    Edit1: TEdit;
    procedure FormCreate(Sender: TObject);
    procedure Edit1Change(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.DFM}

procedure TForm1.FormCreate(Sender: TObject);
{This is a test string to load into the list box at runtime}
CONST ListStrings = 'United States'#13'Guatemala'#13'Mexico'#13+
                    'El Salvador'#13'Costa Rica'#13'Yucatan'#13+
                    'China'#13'Japan'#13'Thailand'#13'Switzerland'#13+
                    'Germany'#13'Lichtenstein'#13'Jamaica'#13'Greece'+
                    'Turkey'#13'Ireland'#13'United Kingdom'#13'Scotland'+
                    'Canada'#13'Uruguay'#13'Paraguay'#13'Cuba'#13+
                    'Spain'#13'Italy'#13'France'#13'Portugal'#13'New Zealand'#13+
                    'Austria'#13'Australia'#13'Philippines'#13'Korea'#13+
                    'Malaysia'#13'Tibet'#13'Nepal'#13'India'#13'Sri Lanka'#13+
                    'Pakistan'#13+'Saudi Arabia'#13'United Arab Emerates'#13'Iran'#13+
                    'Ukraine'#13'Belarus'#13+
                    'Chechen'#13'Yugoslavia'#13'Czechoslovakia'#13'Slovina'#13'Kazakhstan'#13+
                    'Egypt'#13'Morocco'#13'Macedonia'#13'Cyprus'#13'Finland'#13+
                    'Norway'#13'Sweden'#13'Denmark'#13'Netherlands'#13'Lithuania'#13;
begin
  ListBox1.Items.SetText(ListStrings);
end;

procedure TForm1.Edit1Change(Sender: TObject);
var
  S : Array[0..255] of Char;
begin
  StrPCopy(S, Edit1.Text);
  with ListBox1 do
    ItemIndex := Perform(LB_SELECTSTRING, 0, LongInt(@S));
end;

end.
Form1 has two controls: a TEdit and a TListBox. Notice that during FormCreate, I loaded up the value of the list box with the huge string of countries. This step was only for testing purposes. How you load up your list is up to you. Now, the trick to making the incremental search is in the OnChange event of Edit1. I've used the Windows message LB_SELECTSTRING to perform the string selection for me. LB_SELECTSTRING is one of the members of the WinAPI list box message family (all preceeded by LB_) that manipulates all aspects of a list box object in Windows. The message takes two parameters: wParam, the index from which the search should start; and lParam, the address of the null-terminated string to search on. Since WinAPI calls require null-terminated strings, use either a PChar or an Array of Char to pass string values. Using an Array of Char is more advantageous if you know a string value won't exceed a certain length. You don't have to manually allocate and de-allocate memory with an Array of Char, as opposed to a PChar, which requires you to use GetMem or New and FreeMem to allocate and de-allocate memory.

In any case, to convert a Pascal string to a null-terminated string, just use StrPCopy to copy the contents of the Pascal string into the null-terminated string. Once that's done, all you have to do is pass the address of the null-terminated string into the wParam parameter of LB_SELECTSTRING using the @ symbol. When you use Perform to execute the LB_SELECTSTRING message, the message will return the item index of the matching list item. All that's left to do is assign the ItemIndex property of the list box to the return value of the message. The net result is that the list box will scroll to and select the list element that was found.

TListBox has several messages which you can handle and perform in Delphi. If you bring up the help system and do a topic search, enter LB_ in the edit box, and peruse the list of messages.

 
Other 10-Minute Solutions
 Trapping Messages Sent to an Application
 Getting the Number of Records From a Fixed-Length ASCII File
 Performing Incremental Searches with a TListbox
 Resizing the Drop-down List of a TComboBo
 Disabling the System Keys from Your Application
 Making A Secondary Form Independent of the Main Form
 Creating a System Tray Application
 Opening and Closing a CD Tray
 Hiding an Application from Windows
 Make a List Box Track the Mouse
 Running a Program at Startup
 Creating A Skin Component
 Dynamically Load Components From Packages at Run Time
 Obtain All Values from Multivalue Input Fields in WebBroker Applications
 Migrate Your BDE Applications to Linux with dbExpress
 Create a Multiline Button Component
 Update and Maintain dbExpress's Unidirectional, Read-Only Datasets
 Use ActionBands to Enable End Users to Customize Your Delphi Applications
 Produce HTML Reporting Output with WebBroker Components
  Convert XML Documents into Different Formats with the XSL Template Language


Ask the Delphi Pro | Who is the Pro? | Usage Policies | Ask a Question | Search | Feedback


Sponsored Links


Advertising Info  |   Member Services  |   Contact Us  |   Help  |   Feedback  |   Site Map
Jupiterweb networks

internet.comearthweb.comDevx.comClickZ

Search Jupiterweb:

Jupitermedia Corporation has four divisions:
JupiterWeb, JupiterResearch, JupiterEvents, and JupiterImages

Copyright 2004 Jupitermedia Corporation All Rights Reserved.
Legal Notices, Licensing, Reprints, & Permissions, Privacy Policy.

Jupitermedia Corporate Info | Newsletters | Tech Jobs | E-mail Offers