2008. december 13., szombat

Fill In Combo Box (Component)


Problem/Question/Abstract:

In the following article I am going to give you a simple, enhanced combo box, that fills in the text area with possible options from the items list. Simple, but useful.

Note: Delphi 6 does this by default, already

Answer:

INTRODUCTION

In this article I show you how to enhance an already existing component, easily. Because of the nature of this article you should be familar with Delphi already, however, no deep knowledge is needed.

Developing a component is, thanks to Delphi, a rather simple task. You do not have to start from scratch everytime you want to enhance something, already existing. You can simple create a new class and derive it from the one you want to enhance.

GETTING STARTED

In our case we are going to enhance the TComboBox component, directly. We could choose the TCustomComboBox, however, they have different published properties from one Delphi version to another, therefore that want make much sense.

Delphi makes the simple task of creating a new component even more simple by offering a small wizard. From the Menu File | New... select the Component right from the first tab "New."

A simple wizard will show. Fill in accordingly:


Ancestor Type: TComboBox

Class Name: TFillComboBox

Palette Page: Samples (or any you want, i took "Standard")

Unit File Name: Select a folder and file to save your work


Press OK, we will install it at a later time.

The wizard will create a basic component for you, inlcuding the installation routine shown below.

procedure Register;
begin
  RegisterComponents('Standard', [TFillComboBox]);
end;

This routine will be called by Delphi when you select install on your component package including this file. The first parameter of RegisterComponents names the palette page, where the components are installed, the second is an array of the components to be installed.

ADDING A NEW PROPERTY

To our new component we add a new property, called AutomaticFillin. When set to True we will search for a item matching the user input and add the remainder to the text box, otherwise we wont.

Therefore we have to declare one private variable that will save the value of the switch. By puting a property into the published part of the class declaration we allow the Delphi developer to change its value in the Object Inspector.

private
FAutomaticFillin: Boolean;

procedure SetAutomaticFillin(const Value: Boolean);
published
    property AutomaticFillin: Boolean
      read FAutomaticFillin
      write SetAutomaticFillin
      default True;

procedure TFillComboBox.SetAutomaticFillin(const Value: Boolean);
begin
  FAutomaticFillin := Value;
end;

THE PROCESSING OF THE USER CHANGES

In order to become notified when the user changes the text field, we have to override the default message handler for the combo box.

protected

procedure ComboWndProc(
  var Message: TMessage; ComboWnd: HWnd; ComboProc: Pointer
  ); override;

In our implementation, we check first whether the special handling is turned on. If it is turned on, we will get the current text, the user has typed, and then search for it in the items list. If we have a match, we will replace the text with the matching item and select the part added by our function.

THE CODE

If your have followed the directions from the "GETTING STARTED" section, simply replace the unit code with the following code and save your file.

unit FillComboBox;

interface

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

type
  TFillComboBox = class(TComboBox)
  private
    FAutomaticFillin: Boolean;
    procedure SetAutomaticFillin(const Value: Boolean);
  protected
    procedure ComboWndProc(
      var Message: TMessage; ComboWnd: HWnd; ComboProc: Pointer
      ); override;
  public
  published
    constructor Create(AOwner: TComponent); override;
    property AutomaticFillin: Boolean
      read FAutomaticFillin
      write SetAutomaticFillin
      default True;
  end;

procedure Register;

implementation

procedure Register;
begin
  RegisterComponents('Standard', [TFillComboBox]);
end;

{ TFillComboBox }

procedure TFillComboBox.ComboWndProc(
  var Message: TMessage; ComboWnd: HWnd; ComboProc: Pointer
  );
var
  I: Integer;
  CurrentText: string;
begin
  inherited ComboWndProc(Message, ComboWnd, ComboProc);
  // skip processing, if turned off
  if not FAutomaticFillin then
    Exit;
  // first check whether the backspace key was pressed, we do not fill in
  // in such case!
  if Message.Msg = WM_CHAR then
  begin
    // all characters from 32 (Space) through 127 (Upper ANSI) are matched
    if TWMChar(Message).CharCode in [$20..$7F] then
    begin
      // fill in the rest of the text
      // save the current text, the user has typed
      CurrentText := Text;
      // get the first string, matching the text partially
      I := SendMessage(Handle, CB_FINDSTRING, -1, LongInt(PChar(CurrentText)));
      if I >= 0 then
      begin
        // match found!
        // load matching text, I is the position of the matching string
        Text := Items.Strings[I];
        // select the text beyond the text typed
        SelStart := Length(CurrentText);
        SelLength := Length(Text) - Length(CurrentText);
      end;
    end;
  end;
end;

constructor TFillComboBox.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  FAutomaticFillin := True;
end;

procedure TFillComboBox.SetAutomaticFillin(const Value: Boolean);
begin
  FAutomaticFillin := Value;
end;

end.

INSTALLING THE COMPONENT

The last step is to install the component you have just created. Go to the menu and select Component | Install Component.... Select your FillComboBox.pas in the "Unit file name" field and press "OK."

That's all. Now you can create a new application and use the component whenever you feel like.

Nincsenek megjegyzések:

Megjegyzés küldése