Announcement

Collapse
No announcement yet.

Auto-Vervollständigen Eintrag Combo-Box

Collapse
X
  • Filter
  • Time
  • Show
Clear All
new posts

  • Auto-Vervollständigen Eintrag Combo-Box

    Wenn ich in der Liste einer Combo-Box mehrere List-Items eingetragen
    habe, reicht die Angabe des ersten Buchstabens und das anschließende
    Pfeil-Runter zur Anwahl des ersten treffenden Items.

    Ich möchte mit Hilfe einer Combo-Box ein Auto-Vervollständigen haben :
    Beispiel :
    Cb.Text := 'GB' => Anzeige/cb.Text wird zu 'GB Grossbritanien';

    Geht das ? Wenn ja wie ?

  • #2
    Hallo,

    >Geht das?

    Ja.

    >Wenn ja wie?

    Immer dann, wenn der Internet Explorer 5.x (oder höher) und somit eine neuere Version von <i>Shell32.dll</i> installiert ist, stellt das Betriebssystem bestimmte vordefinierte AutoComplete-Funktionen zur Verfügung. Über die Win32-API-Funktion <b>SHAutoComplete</b> wird das Betriebssystem beauftragt, sich um die Details zu kümmern.

    Wenn eine TComboBox-Instanz eigene Zeichenketten zur Laufzeit dynamisch erweiterbar über AutoComplete verwendet werden sollen, ist der Aufwand etwas höher. Es liegt auf der Hand, dass hier eine Interaktion zwischen der eigenen Anwendung und dem für AutoComplete zuständigen Teil - also dem Betriebssystem selbst - notwendig ist. Das <b>IEnumString</B>-Interface ist ein von COM vordefiniertes Interface für Enumerations-Objekte, die eine Kollektion von BSTRs (also der in COM üblichen Strings) verwalten. Das Betriebssystem erwartet, dass die eigene Anwendung ein COM-Objekt implementiert, dass über IEnumStrings "abgefragt" werden kann. Die abzuarbeitenden Schritte lassen sich wie folgt zusammenfassen:<br>
    - Anwendung verwendet eine TStringList-Instanz für die Verwaltung der Zeichenketten <br>
    - Anwendung implementiert ein COM-Objekt für IEnumString <br>
    - Anwendung initilialisiert AutoComplete, indem das IEnumString-Objekt übergeben wird <br>
    - Windows kümmert sich um den Rest

    Im Detail sieht das dann so aus:
    <pre>
    // TEdit - AutoComplete für eine eigene Stringliste
    FStringList := TStringList.Create;
    FStringList.Add('Berlin');
    FStringList.Add('Erfurt');
    FStringList.Sorted := True;
    FStringList.Duplicates := dupIgnore;
    // Interface-Zeiger für IAutoComplete2 anfordern
    FAutoComplete := CreateComObject(CLSID_AutoComplete) as IAutoComplete2;
    OleCheck(FAutoComplete.SetOptions(ACO_AUTOSUGGEST
    or ACO_AUTOAPPEND or ACO_UPDOWNKEYDROPSLIST or ACO_USETAB));
    // IEnumStrings-Objekt als Zeichenketten-Puffer zuordnen
    FStringsObj := TEnumString.Create(FStringList) as IUnknown;
    OleCheck(FAutoComplete.Init(Edit1.Handle, FStringsObj, nil, nil));
    </pre>
    Der fehlende Rest besteht zum einen wiederum aus der nachgeholten Deklaration der in Delphi fehlenden Sachen sowie in der Implementierung des IEnumString-Objekts. Allerdings stellt Delphi bereits eine Kopiervorlage für dieses COM-Objekt zur Verfügung, so dass zumindestens dieser Teil sehr schnell erledigt ist. Ein vollständiges Beispiel sieht dann so aus:
    <pre>
    { ************************************************** *******************
    Autor : Andreas Kosch
    Compiler : Delphi 5 UpdatePack#1
    Betriebssystem : Windows 2000
    Datum : 27.08.2000
    Beschreibung : SHAutoComplete
    ************************************************** ******************** }

    unit IAutoCompleteTest2Frm;

    interface

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

    type
    IAutoComplete = interface(IUnknown)
    ['{00BB2762-6A77-11D0-A535-00C04FD7D062}']
    function Init(hwndEdit: HWND; punkACL: IUnknown; pwszRegKeyPath: PWideChar;
    pwszQuickComplete: PWideChar): HResult; stdcall;
    function Enable(fEnable: Boolean): HResult; stdcall;
    end;

    IAutoComplete2 = interface(IAutoComplete)
    ['{EAC04BC0-3791-11D2-BB95-0060977B464C}']
    function SetOptions(dwFlag: DWORD): HResult; stdcall;
    function GetOptions(out dwFlag: DWORD): HResult; stdcall;
    end;

    TForm1 = class(TForm)
    Edit1: TEdit;
    StatusBar1: TStatusBar;
    Label1: TLabel;
    Button1: TButton;
    ListBox1: TListBox;
    ComboBox1: TComboBox;
    procedure FormCreate(Sender: TObject);
    procedure Button1Click(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure Edit1Exit(Sender: TObject);
    private
    { Private-Deklarationen }
    FAutoComplete : IAutoComplete2;
    FStringsObj : IUnknown;
    FStringList : TStringList;
    FHandle : HWND;
    public
    { Public-Deklarationen }
    end;

    var
    Form1: TForm1;

    implementation

    {$R *.DFM}

    // shlwapi.h - Interface for the Windows light-weight utility APIs

    uses CommCtrl;

    const
    SHACF_DEFAULT = 0;
    SHACF_FILESYSTEM = 1;
    SHACF_AUTOSUGGEST_FORCE_ON = $10000000;
    SHACF_AUTOAPPEND_FORCE_ON = $40000000;
    ACO_AUTOSUGGEST = $0001;
    ACO_AUTOAPPEND = $0002;
    ACO_SEARCH = $0004;
    ACO_FILTERPREFIXES = $0008;
    ACO_USETAB = $0010;
    ACO_UPDOWNKEYDROPSLIST = $0020;
    ACO_RTLREADING = $0040;

    CLSID_AutoComplete: TGUID = (
    D1:$00BB2763; D2:$6A77; D3:$11D0; D4$A5,$35,$00,$C0,$4F,$D7,$D0,$62));

    function SHAutoComplete(hWndEdit : HWND;
    dwFlags: DWORD): HRESULT; stdcall;
    external 'Shlwapi.dll';

    {---------------------------------------------------------------------}
    { TEnumString implementiert IEnumString }
    {---------------------------------------------------------------------}

    type
    TEnumString = class(TInterfacedObject, IEnumString)
    private
    FStrings : TStrings;
    FIndex : Integer;
    protected
    function Next(celt: Longint; out elt;
    pceltFetched: PLongint): HResult; stdcall;
    function Skip(celt: Longint): HResult; stdcall;
    function Reset: HResult; stdcall;
    function Clone(out enm: IEnumString): HResult; stdcall;
    public
    constructor Create(Strings: TStrings);
    end;

    constructor TEnumString.Create(Strings: TStrings);
    begin
    inherited Create;
    FStrings := Strings;
    end;

    function TEnumString.Next(celt: Longint;
    out elt; pceltFetched: PLongint): HResult;
    var
    I: Integer;
    begin
    I := 0;
    while (I < celt) and (FIndex < FStrings.Count) do
    begin
    TPointerList(elt)[I] := PWideChar(WideString(FStrings[FIndex]));
    Inc(I);
    Inc(FIndex);
    end;
    if pceltFetched <> nil then pceltFetched^ := I;
    if I = celt then Result := S_OK else Result := S_FALSE;
    end;

    function TEnumString.Skip(celt: Longint): HResult;
    begin
    if (FIndex + celt) <= FStrings.Count then
    begin
    Inc(FIndex, celt);
    Result := S_OK;
    end
    else
    begin
    FIndex := FStrings.Count;
    Result := S_FALSE;
    end;
    end;

    function TEnumString.Reset: HResult;
    begin
    FIndex := 0;
    Result := S_OK;
    end;

    function TEnumString.Clone(out enm: IEnumString): HResult;
    begin
    try
    enm := TEnumString.Create(FStrings);
    Result := S_OK;
    except
    Result := E_UNEXPECTED;
    end;
    end;

    {---------------------------------------------------------------------}
    { Beispielanwendung }
    {---------------------------------------------------------------------}

    procedure TForm1.FormCreate(Sender: TObject);
    begin
    // TComboBox - AutoComplete für Dateinamen
    ComboBox1.HandleNeeded;
    FHandle := GetWindow(ComboBox1.Handle, GW_CHILD);
    OleCheck(SHAutoComplete(FHandle,
    SHACF_AUTOAPPEND_FORCE_ON or SHACF_FILESYSTEM));
    // TEdit - AutoComplete für eine eigene Stringliste
    FStringList := TStringList.Create;
    FStringList.Add('Berlin');
    FStringList.Add('Erfurt');
    FStringList.Sorted := True;
    FStringList.Duplicates := dupIgnore;
    // Interface-Zeiger für IAutoComplete2 anfordern
    FAutoComplete := CreateComObject(CLSID_AutoComplete)as IAutoComplete2;
    OleCheck(FAutoComplete.SetOptions(ACO_AUTOSUGGEST
    or ACO_AUTOAPPEND or ACO_UPDOWNKEYDROPSLIST or ACO_USETAB));
    // IEnumStrings-Objekt als Zeichenketten-Puffer zuordnen
    FStringsObj := TEnumString.Create(FStringList) as IUnknown;
    OleCheck(FAutoComplete.Init(Edit1.Handle, FStringsObj, nil, nil));
    end;

    procedure TForm1.Edit1Exit(Sender: TObject);
    begin
    FStringList.Add(Edit1.Text);
    end;

    procedure TForm1.Button1Click(Sender: TObject);
    begin
    ListBox1.Items.Add(Edit1.Text);
    Edit1.Text := '';
    end;

    procedure TForm1.FormDestroy(Sender: TObject);
    begin
    FStringList.Free;
    end;

    end.
    </pre&gt

    Comment

    Working...
    X