⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 jvqautocomplete.pas

📁 East make Tray Icon in delphi
💻 PAS
📖 第 1 页 / 共 2 页
字号:
{******************************************************************************}
{* WARNING:  JEDI VCL To CLX Converter generated unit.                        *}
{*           Manual modifications will be lost on next release.               *}
{******************************************************************************}

{-----------------------------------------------------------------------------
The contents of this file are subject to the Mozilla Public License
Version 1.1 (the "License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.mozilla.org/MPL/MPL-1.1.html

Software distributed under the License is distributed on an "AS IS" basis,
WITHOUT WARRANTY OF ANY KIND, either expressed or implied. See the License for
the specific language governing rights and limitations under the License.

The Original Code is: JvAutoComplete.pas, released on 2004-09-04.

The Initial Developer of the Original Code is Andreas Hausladen [Andreas dott Hausdaden att gmx dott de]
Portions created by Andreas Hausladen are Copyright (C) 2004 Andreas Hausladen.
All Rights Reserved.

You may retrieve the latest version of this file at the Project JEDI's JVCL home page,
located at http://jvcl.sourceforge.net

Known Issues:
-----------------------------------------------------------------------------}
// $Id: JvQAutoComplete.pas,v 1.4 2005/02/06 14:06:00 asnepvangers Exp $

unit JvQAutoComplete;

{$I jvcl.inc}

interface

uses
  QWindows, 
  SysUtils, Classes, QControls, QStdCtrls;

type
  { TControlAutoComplete implements a autocomplete code for a controls it is a
    abstract base class. After you have created an instance of a derived class
    you must either assign the AutoCompleteEvent to the OnKeyPress event of the
    control or you must call the AutoComplete method from in a KeyPress event
    handler.


    (ahuser) 2005-01-31: changed from TObject to TComponent due to Notification()
    Do not register this component it is more a "TObject" than a TComponent. }
  TJvControlAutoComplete = class(TComponent)
  private
    FFilter: string;
    FLastTime: Cardinal;
    FMaxFilterTime: Cardinal;
    FListSearch: Boolean;
    FActive: Boolean;
    FOnDropDown: TNotifyEvent;
    FOnValidateItems: TNotifyEvent;
    FOnChange: TNotifyEvent;
    FOnValueChange: TNotifyEvent;
  protected
    function GetText: TCaption; virtual; abstract;
    procedure SetText(const Value: TCaption); virtual; abstract;
    procedure GetEditSel(out StartPos, EndPos: Integer); virtual; abstract;
    procedure SetEditSel(StartPos, EndPos: Integer); virtual; abstract;
    procedure SetItemIndex(Index: Integer); virtual; abstract;
    function GetItemIndex: Integer; virtual; abstract;
    function FindItemPrefix(IndexStart: Integer; const Prefix: string): Integer; virtual; abstract;
    function GetItemAt(Index: Integer): string; virtual; abstract; 

    function GetActive: Boolean; virtual;
    procedure SetFilter(const Value: string);

    procedure DoDropDown; dynamic;
    procedure DoValidateItems; dynamic;
    procedure DoChange; dynamic;
    procedure DoValueChange; dynamic;
  public
    constructor Create; reintroduce;
    procedure AutoCompleteEvent(Sender: TObject; var Key: Char);
    procedure AutoComplete(var Key: Char); virtual;

    property ListSearch: Boolean read FListSearch write FListSearch; // no edit possible
    property MaxFilterTime: Cardinal read FMaxFilterTime write FMaxFilterTime; // only with ListSearch

    property Active: Boolean read GetActive write FActive;
    property OnDropDown: TNotifyEvent read FOnDropDown write FOnDropDown;
    property OnValidateItems: TNotifyEvent read FOnValidateItems write FOnValidateItems;
    property OnChange: TNotifyEvent read FOnChange write FOnChange;
    property OnValueChange: TNotifyEvent read FOnValueChange write FOnValueChange;
  end;

  TJvBaseEditListAutoComplete = class(TJvControlAutoComplete)
  private
    FEditCtrl: TCustomEdit;
    FList: TStrings;
    procedure SetEditCtrl(Value: TCustomEdit);
  protected
    procedure Notification(AComponent: TComponent; Operation: TOperation); override;
    function GetText: TCaption; override;
    procedure SetText(const Value: TCaption); override;
    procedure GetEditSel(out StartPos, EndPos: Integer); override;
    procedure SetEditSel(StartPos, EndPos: Integer); override;
    function FindItemPrefix(IndexStart: Integer; const Prefix: string): Integer; override;
    function GetItemAt(Index: Integer): string; override; 
    function GetActive: Boolean; override;
    property List: TStrings read FList write FList;
  public
    constructor Create(AEditCtrl: TCustomEdit; AList: TStrings);
    destructor Destroy; override;
    property EditCtrl: TCustomEdit read FEditCtrl write SetEditCtrl;
  end;

  { TEditListAutoComplete implements a autocomplete code for a Edit/TStrings
    pair. After you have created an instance of this class you must either
    assign the AutoCompleteEvent to the OnKeyPress event of the edit control
    or you must call the AutoComplete method from in a KeyPress event handler. }
  TJvEditListAutoComplete = class(TJvBaseEditListAutoComplete)
  private
    FOnItemIndexChange: TNotifyEvent;
    FOnValidateItemIndex: TNotifyEvent;
  public
    FItemIndex: Integer;
    function GetList: TStrings;
    procedure SetList(Value: TStrings);
    procedure SetInternalItemIndex(Value: Integer);
  protected
    procedure SetItemIndex(Index: Integer); override;
    function GetItemIndex: Integer; override;
  public
    constructor Create(AEditCtrl: TCustomEdit; AList: TStrings);
    property ItemIndex: Integer read FItemIndex write SetInternalItemIndex;
    property List: TStrings read GetList write SetList;
    property OnItemIndexChange: TNotifyEvent read FOnItemIndexChange write FOnItemIndexChange;
    property OnValidateItemIndex: TNotifyEvent read FOnValidateItemIndex write FOnValidateItemIndex;
  end;

  { TEditListBoxAutoComplete implements a autocomplete code for a Edit/ListBox
    pair. After you have created an instance of this class you must either
    assign the AutoCompleteEvent to the OnKeyPress event of the edit control
    or you must call the AutoComplete method from in a KeyPress event handler. }
  TJvEditListBoxAutoComplete = class(TJvBaseEditListAutoComplete)
  private
    FListBox: TCustomListBox;
    procedure SetListBox(Value: TCustomListBox);
  protected
    procedure SetItemIndex(Index: Integer); override;
    function GetItemIndex: Integer; override;
    procedure Notification(AComponent: TComponent; Operation: TOperation); override;
  public
    constructor Create(AEditCtrl: TCustomEdit; AListBox: TCustomListBox);
    destructor Destroy; override;
    property ListBox: TCustomListBox read FListBox write SetListBox;
  end;

  { TComboBoxAutoComplete implements a autocomplete code for a ComboBox.
    After you have created an instance of this class you must either assign the
    AutoCompleteEvent to the OnKeyPress event of the edit control or you must
    call the AutoComplete method from in a KeyPress event handler. }
  TJvComboBoxAutoComplete = class(TJvControlAutoComplete)
  private
    FComboBox: TCustomComboBox;
    procedure SetComboBox(Value: TCustomComboBox);
  protected
    function GetText: TCaption; override;
    procedure SetText(const Value: TCaption); override;
    procedure GetEditSel(out StartPos, EndPos: Integer); override;
    procedure SetEditSel(StartPos, EndPos: Integer); override;
    procedure SetItemIndex(Index: Integer); override;
    function GetItemIndex: Integer; override;
    function FindItemPrefix(IndexStart: Integer; const Prefix: string): Integer; override;
    function GetItemAt(Index: Integer): string; override; 
    function GetActive: Boolean; override;
  public
    constructor Create(AComboBox: TCustomComboBox);
    property ComboBox: TCustomComboBox read FComboBox write SetComboBox;
  end;

  TJvLookupAutoCompleteKind = (akListBox, akStrings);

  TJvLookupAutoComplete = class(TComponent)
  private
    FAutoComplete: TJvEditListAutoComplete;
    FListBox: TCustomListBox;
    FStrings: TStrings;
    FKind: TJvLookupAutoCompleteKind;
    FOrgKeyPress: TKeyPressEvent;
    FOnChange: TNotifyEvent;
    FOnValidateStrings: TNotifyEvent;
    FOnDropDown: TNotifyEvent;
    FOnValueChange: TNotifyEvent;
    function GetEdit: TCustomEdit;
    function GetItemIndex: Integer;
    function GetListSearch: Boolean;
    procedure SetEdit(Value: TCustomEdit);
    procedure SetItemIndex(Value: Integer);
    procedure SetKind(Value: TJvLookupAutoCompleteKind);
    procedure SetListBox(Value: TCustomListBox);
    procedure SetListSearch(Value: Boolean);
    procedure SetStrings(Value: TStrings);
    function GetActive: Boolean;
    procedure SetActive(const Value: Boolean);
  protected
    procedure Notification(AComponent: TComponent; Operation: TOperation); override;
    procedure EvKeyPress(Sender: TObject; var Key: Char); dynamic;
    procedure EvDropDown(Sender: TObject); dynamic;
    procedure EvValidateStrings(Sender: TObject); dynamic;
    procedure EvChange(Sender: TObject); dynamic;
    procedure EvValueChange(Sender: TObject); dynamic;
    procedure EvItemIndexChange(Sender: TObject); dynamic;
    procedure EvValidateItemIndex(Sender: TObject); dynamic;
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;

    property ItemIndex: Integer read GetItemIndex write SetItemIndex;
  published
    property Active: Boolean read GetActive write SetActive default True;
    property Edit: TCustomEdit read GetEdit write SetEdit;
    property ListBox: TCustomListBox read FListBox write SetListBox;
    property Strings: TStrings read FStrings write SetStrings;
    property Kind: TJvLookupAutoCompleteKind read FKind write SetKind default akListBox;
    property ListSearch: Boolean read GetListSearch write SetListSearch default False;
    property OnDropDown: TNotifyEvent read FOnDropDown write FOnDropDown;
    property OnValidateStrings: TNotifyEvent read FOnValidateStrings write FOnValidateStrings;
    property OnChange: TNotifyEvent read FOnChange write FOnChange;
    property OnValueChange: TNotifyEvent read FOnValueChange write FOnValueChange;
  end;

implementation

uses
  {$IFDEF UNITVERSIONING}
  JclUnitVersioning,
  {$ENDIF UNITVERSIONING}
  JvQConsts, JvQJCLUtils;

//=== { TJvControlAutoComplete } =============================================

constructor TJvControlAutoComplete.Create;
begin
  inherited Create(nil);
  FActive := True;
  FMaxFilterTime := 500;
end;

function TJvControlAutoComplete.GetActive: Boolean;
begin
  Result := FActive;
end;

procedure TJvControlAutoComplete.SetFilter(const Value: string);
begin
  FFilter := Value;
end;

procedure TJvControlAutoComplete.DoValidateItems;
begin
  if Assigned(FOnValidateItems) then
    FOnValidateItems(Self);
end;

procedure TJvControlAutoComplete.DoChange;
begin
  if Assigned(FOnChange) then
    FOnChange(Self);
end;

procedure TJvControlAutoComplete.DoDropDown;
begin
  if Assigned(FOnDropDown) then
    FOnDropDown(Self);
end;

procedure TJvControlAutoComplete.DoValueChange;
begin
  if Assigned(FOnValueChange) then
    FOnValueChange(Self);
end;

procedure TJvControlAutoComplete.AutoCompleteEvent(Sender: TObject; var Key: Char);
begin
  AutoComplete(Key);
end;

procedure TJvControlAutoComplete.AutoComplete(var Key: Char);
var
  StartPos, EndPos: Integer;
  SaveText, OldText: TCaption;
  LastByte: Integer;
  LT: Int64; 

  function HasSelectedText(var StartPos, EndPos: Integer): Boolean;
  begin
    GetEditSel(StartPos, EndPos);
    Result := EndPos > StartPos;
  end;

  procedure DeleteSelectedText;
  var
    StartPos, EndPos: Integer;
    OldText: string;
  begin
    OldText := GetText;
    GetEditSel(StartPos, EndPos);
    Delete(OldText, StartPos + 1, EndPos - StartPos);
    SetItemIndex(-1);
    SetText(OldText);
    SetEditSel(StartPos, StartPos);
  end;

  function SelectItem(const AnItem: string): Boolean;
  var
    Idx: Integer;
    ValueChange: Boolean;
  begin
    if AnItem = '' then
    begin
      Result := False;
      SetItemIndex(-1);
      DoChange;
      Exit;
    end;
    Idx := FindItemPrefix(-1, AnItem);
    Result := (Idx <> -1);
    if not Result then
      Exit;
    ValueChange := Idx <> GetItemIndex;
    SetItemIndex(Idx);
    if ListSearch then
    begin
      SetItemIndex(Idx);
      FFilter := AnItem;
    end
    else
    begin
      SetText(AnItem + Copy(GetItemAt(Idx), Length(AnItem) + 1, MaxInt));
      SetEditSel(Length(AnItem), Length(GetText));
    end;
    if ValueChange then
      DoValueChange;
  end;

begin
  if not Active then
    Exit;

  if ListSearch then
  begin
    LT := GetTickCount;
    if FLastTime > LT then
      LT := $100000000 + LT; // double limit.
    if LT - FLastTime >= MaxFilterTime then
      FFilter := '';
    FLastTime := GetTickCount;
  end
  else
    FFilter := GetText;

  case Key of
    Esc {VK_ESCAPE}:
      Exit;
    Tab {VK_TAB}:
      begin
        DoValidateItems;
        DoDropDown;
      end;
    BackSpace {VK_BACK}:
      begin
        DoValidateItems;
        if HasSelectedText(StartPos, EndPos) then
          DeleteSelectedText
        else
        if not ListSearch and (GetText <> '') then
        begin
          SaveText := GetText;
          LastByte := StartPos; 
          OldText := Copy(SaveText, 1, LastByte - 1);
          SetItemIndex(-1);
          SetText(OldText + Copy(SaveText, EndPos + 1, MaxInt));
          SetEditSel(LastByte - 1, LastByte - 1);
          FFilter := GetText;
        end
        else
        begin
          while ByteType(FFilter, Length(FFilter)) = mbTrailByte do
            Delete(FFilter, Length(FFilter), 1);
          Delete(FFilter, Length(FFilter), 1);
        end;
        Key := #0;
        DoChange;
      end;
  else
    DoValidateItems;
    DoDropDown;

    if HasSelectedText(StartPos, EndPos) then
      SaveText := Copy(FFilter, 1, StartPos) + Key
    else
      SaveText := FFilter + Key;
 
    if SelectItem(SaveText) then
      Key := #0;
  end;
end;

//=== { TJvBaseEditListAutoComplete } ========================================

constructor TJvBaseEditListAutoComplete.Create(AEditCtrl: TCustomEdit;
  AList: TStrings);
begin
  inherited Create;
  FList := AList;
  EditCtrl := AEditCtrl;
end;

destructor TJvBaseEditListAutoComplete.Destroy;
begin
  EditCtrl := nil;
  inherited Destroy;
end;

procedure TJvBaseEditListAutoComplete.Notification(AComponent: TComponent;
  Operation: TOperation);
begin
  if (Operation = opRemove) and (AComponent = FEditCtrl) then
  begin
    FEditCtrl := nil;
    SetFilter('');
  end;
  inherited Notification(AComponent, Operation);
end;

procedure TJvBaseEditListAutoComplete.SetEditCtrl(Value: TCustomEdit);
begin
  if Assigned(FEditCtrl) then
    FEditCtrl.RemoveFreeNotification(Self);
  FEditCtrl := Value;
  if Assigned(FEditCtrl) then
    FEditCtrl.FreeNotification(Self);

  if FEditCtrl <> nil then
    SetFilter(FEditCtrl.Text)
  else
    SetFilter('');
end;

type
  TCustomEditAccess = class(TCustomEdit);

function TJvBaseEditListAutoComplete.GetText: TCaption;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -