Foros Club Delphi

Foros Club Delphi (https://www.clubdelphi.com/foros/index.php)
-   Varios (https://www.clubdelphi.com/foros/forumdisplay.php?f=11)
-   -   Autocompletar en TEdit (https://www.clubdelphi.com/foros/showthread.php?t=84100)

santiago14 17-03-2014 13:35:22

Cita:

Empezado por nlsgarcia (Mensaje 466884)
santiago14,


Recuerda que en las versiones anteriores (v1, v2 y v3) siempre existió el archivo histórico por defecto 'History.txt', pero si no se llama el método LoadHistory (v2 y v3) el ComboBox Modificado funcionara como un ComboBox estándar.



Revisa este código:
Código Delphi [-]
unit Unit1;

interface

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

type
  TComboBox = class(StdCtrls.TComboBox)
  private
    CtrlLoad : Boolean;
    UnFlicker : Boolean;
    UpDown : Boolean;
    AuxText : String;
    HistoryName : String;
    StoredItems : TStringList;
    CountItems : Byte;
    procedure FilterItems;
    procedure StoredItemsChange(Sender: TObject);
    procedure LoadHistory(FileHistory : String = ''; CountHistory : Byte = 10);
    procedure ComboExit(Sender: TObject);
    procedure ComboCloseUp(Sender: TObject);
    procedure ComboKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
    procedure CNCommand(var Message: TWMCommand); Message CN_COMMAND;
  protected
  public
    constructor Create(Owner: TComponent); override;
    destructor Destroy; override;
  end;

type
  TForm1 = class(TForm)
    ComboBox1 : TComboBox;
    ComboBox2: TComboBox;
    ComboBox3: TComboBox;
    ComboBox4: TComboBox;
    Button1 : TButton;
    ComboBox5: TComboBox;
    procedure Button1Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
  private
  public
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

constructor TComboBox.Create(Owner: TComponent);
begin

   inherited;

   AutoComplete := False;
   StoredItems := TStringList.Create;
   StoredItems.OnChange := StoredItemsChange;
   Self.OnExit := ComboExit;
   Self.OnCloseUp := ComboCloseUp;
   Self.OnKeyDown := ComboKeyDown;
   UnFlicker := False;
   CtrlLoad := False;

end;

destructor TComboBox.Destroy;
begin
   StoredItems.Free;
   inherited;
end;

procedure TComboBox.LoadHistory(FileHistory : String = ''; CountHistory : Byte = 10);
begin

   CtrlLoad := True;

   Self.DropDownCount := CountHistory;
   CountItems := CountHistory;

   if FileHistory = EmptyStr then
      HistoryName := 'History_' + Self.Name + '.txt'
   else
      HistoryName := FileHistory;

   if FileExists(HistoryName) then
      Self.StoredItems.LoadFromFile(HistoryName);

end;

procedure TComboBox.CNCommand(var Message: TWMCommand);
begin

   inherited;

   if Message.NotifyCode = CBN_EDITUPDATE then
      FilterItems;

end;

procedure TComboBox.FilterItems;
var
   i : Integer;
   StartPos, EndPos : Integer;

begin

   SendMessage(Handle, CB_GETEDITSEL, WPARAM(@StartPos), LPARAM(@EndPos));

   AuxText := Text;

   if Text <> EmptyStr then
   begin

      Items.Clear;

      for i := 0 to StoredItems.Count - 1 do
      begin
         if PosEx(LowerCase(Text), LowerCase(StoredItems[i])) > 0 then
            Items.Add(StoredItems[i]);
      end;

   end
   else
      Items.Assign(StoredItems);

   if UnFlicker then
      SendMessage(Handle, CB_SHOWDROPDOWN, Integer(True), 0);

   Text := AuxText;

   SendMessage(Handle, CB_SETEDITSEL, 0, MakeLParam(StartPos, EndPos));

   UnFlicker := True;

end;

procedure TComboBox.StoredItemsChange(Sender: TObject);
begin

   if Assigned(StoredItems) then
      FilterItems;

end;

procedure TComboBox.ComboExit(Sender: TObject);
var
   i : Integer;

begin

   if (Items.IndexOf(Text) = -1) and (Text <> EmptyStr) and CtrlLoad then
   begin
      StoredItems.Insert(0,Text);
      for i := StoredItems.Count - 1 downto CountItems do
         StoredItems.Delete(i);
      StoredItems.SaveToFile(HistoryName);
      Self.ItemIndex := 0;
   end;

end;

procedure TComboBox.ComboCloseUp(Sender: TObject);
begin

   If (AuxText <> EmptyStr) and (UpDown = False) then
   begin
      Text := AuxText;
   end;

   UpDown := False;

end;

procedure TComboBox.ComboKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
begin
   if (Key = VK_UP) or (Key = VK_DOWN) then
      UpDown := True;
end;

procedure TForm1.Button1Click(Sender: TObject);
var
   i : Integer;

begin

   for i := 0 to ComponentCount - 1 do
   begin
      if Components[i] is TComboBox then
      begin
         if TComboBox(Components[i]).Text <> EmptyStr then
            ShowMessage(TComboBox(Components[i]).Text);
      end;
   end;

end;

procedure TForm1.FormCreate(Sender: TObject);
begin

   // Archivo Histórico definido por el usuario y por defecto 10 items por archivo
   ComboBox1.LoadHistory('History_1.txt');

   // Archivo Histórico definido por el usuario y 12 items por archivo
   ComboBox2.LoadHistory('History_2.txt',12);

   // Archivo Histórico definido por defecto ('History_' + Self.Name + '.txt') y 10 items por archivo
   ComboBox3.LoadHistory;

   // Archivo Histórico definido por defecto ('History_' + Self.Name + '.txt') y 5 items por archivo
   ComboBox4.LoadHistory('',5);

   // ComboBox5 no usa el método LoadHistory y por lo tanto se comporta como un Combobox Estándar

end;

end.
El código anterior es la Versión 4 del código sugerido en el Msg #16 que permite: Simular de forma básica la función SHAutoComplete en un componente TComboBox modificado.

Notas:

1- El método LoadHistory permite definir el Archivo Histórico y su Cantidad Máxima de Items, asociado al ComboBox Modificado.

2- Si se llama el método LoadHistory sin parámetros, se creara por defecto el archivo 'History_' + Self.Name + '.txt' con un límite máximo de 10 items.

3- Los Items ahora son Insertados al principio de la lista en lugar de Adicionados al final de esta, por lo tanto esta será de reiniciación cíclica en función del número máximo de items por archivo definidos explicita o implícitamente en el método LoadHistory.

4- El número máximo de Items por archivo histórico es 255.

5- Si se omite el método LoadHistory, el ComboBox Modificado funcionara como un ComboBox estándar.

El ejemplo esta disponible en el link: http://terawiki.clubdelphi.com/Delph...omboBox+V4.rar

Espero sea útil :)

Nelson.

Vuelvo al ruedo con este tema después de tanto tiempo.
Resulta que está muy bueno y ahora quiero ponerlo en una Unit como una clase para poder usarlo siempre y en diversas aplicaciones.
Lo puse en una Unit particular (oAutocompletar.pas) y al momento de compilar me dice: [error] File not found oAutocompletar.dfm

¿Qué está faltando?

Gracias.

santiago14 17-03-2014 15:46:38

Muestro lo que hice yo, de seguro este es el problema....:)

Código Delphi [-]
unit oAutocompletarCombo;

interface

uses
  StrUtils, Classes, Messages, Controls, SysUtils, Windows, StdCtrls;

type
  TComboBoxAutocomplete = class(TComboBox)
  private
    CtrlLoad : Boolean;
    UnFlicker : Boolean;
    UpDown : Boolean;
    AuxText : String;
    HistoryName : String;
    StoredItems : TStringList;
    CountItems : Byte;
    procedure FilterItems;
    procedure CNCommand(var Message: TWMCommand); Message CN_COMMAND;
  public
    procedure StoredItemsChange(Sender: TObject);
    procedure LoadHistory(FileHistory : String = ''; CountHistory : Byte = 10);
      procedure ComboExit(Sender: TObject);
    procedure ComboCloseUp(Sender: TObject);
    procedure ComboKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
    constructor Create(Owner: TComponent); override;
    destructor Destroy; override;
  end;

implementation

{$R *.dfm}

constructor TComboBoxAutocomplete.Create(Owner: TComponent);
begin
   inherited;
   AutoComplete := False;
   StoredItems := TStringList.Create;
   StoredItems.OnChange := StoredItemsChange;
   Self.OnExit := ComboExit;
   Self.OnCloseUp := ComboCloseUp;
   Self.OnKeyDown := ComboKeyDown;
   UnFlicker := False;
   CtrlLoad := False;
end;

destructor TComboBoxAutocomplete.Destroy;
begin
   StoredItems.Free;
   inherited;
end;

procedure TComboBoxAutocomplete.LoadHistory(FileHistory : String = ''; CountHistory : Byte = 10);
begin
   CtrlLoad := True;
   Self.DropDownCount := CountHistory;
   CountItems := CountHistory;
   if FileHistory = EmptyStr then
      HistoryName := 'History_' + Self.Name + '.txt'
   else
      HistoryName := FileHistory;
   if FileExists(HistoryName) then
      Self.StoredItems.LoadFromFile(HistoryName);
end;

procedure TComboBoxAutocomplete.CNCommand(var Message: TWMCommand);
begin
   inherited;
   if Message.NotifyCode = CBN_EDITUPDATE then
      FilterItems;
end;

procedure TComboBoxAutocomplete.FilterItems;
var
   i : Integer;
   StartPos, EndPos : Integer;
begin
   SendMessage(Handle, CB_GETEDITSEL, WPARAM(@StartPos), LPARAM(@EndPos));
   AuxText := Text;
   if Text <> EmptyStr then
   begin
      Items.Clear;
      for i := 0 to StoredItems.Count - 1 do
      begin
         if PosEx(LowerCase(Text), LowerCase(StoredItems[i])) > 0 then
            Items.Add(StoredItems[i]);
      end;
   end
   else
      Items.Assign(StoredItems);
   if UnFlicker then
      SendMessage(Handle, CB_SHOWDROPDOWN, Integer(True), 0);
   Text := AuxText;
   SendMessage(Handle, CB_SETEDITSEL, 0, MakeLParam(StartPos, EndPos));
   UnFlicker := True;
end;

procedure TComboBoxAutocomplete.StoredItemsChange(Sender: TObject);
begin
   if Assigned(StoredItems) then
      FilterItems;
end;

procedure TComboBoxAutocomplete.ComboExit(Sender: TObject);
var
   i : Integer;
begin
   if (Items.IndexOf(Text) = -1) and (Text <> EmptyStr) and CtrlLoad then
   begin
      StoredItems.Insert(0,Text);
      for i := StoredItems.Count - 1 downto CountItems do
         StoredItems.Delete(i);
      StoredItems.SaveToFile(HistoryName);
      Self.ItemIndex := 0;
   end;
end;

procedure TComboBoxAutocomplete.ComboCloseUp(Sender: TObject);
begin
   If (AuxText <> EmptyStr) and (UpDown = False) then
   begin
      Text := AuxText;
   end;
   UpDown := False;
end;

procedure TComboBoxAutocomplete.ComboKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
begin
   if (Key = VK_UP) or (Key = VK_DOWN) then
      UpDown := True;
end;

end.

ecfisa 18-03-2014 00:55:48

Cita:

Empezado por santiago14 (Mensaje 473897)
...
Lo puse en una Unit particular (oAutocompletar.pas) y al momento de compilar me dice: [error] File not found oAutocompletar.dfm

¿Qué está faltando?

Hola santiago14.

En realidad la pregunta es ¿ Qué está sobrando ? :)

Quitá la línea:
Código Delphi [-]
{$R *.dfm}

Saludos :)

santiago14 18-03-2014 12:31:42

Gracias ecfisa, me sobraba la directiva de compilación....

Santiago.

santiago14 19-03-2014 16:39:10

Funciona muy bien el comboBox con el autocompletado.
Resulta que ahora, mientras estoy escribiendo dentro del Combo "desaparece" la flecha del mouse. La única forma de recuperarlo es haciendo click en algún lugar del formulario que contiene el combo.
Si bien no es un gran defecto, para el usuario final que usa esto, le es molesto.

Espero poder encontrarle la vuelta.

Santiago.

nlsgarcia 19-03-2014 19:36:14

santiago14,

Cita:

Empezado por santiago14
...mientras estoy escribiendo dentro del Combo "desaparece" la flecha del mouse. La única forma de recuperarlo es haciendo click en algún lugar del formulario...

Puedes recuperar durante la edición del ComboBox, la flecha del Mouse actualmente activa presionado la tecla Esc.

Espero sea útil :)

Nelson.


La franja horaria es GMT +2. Ahora son las 17:52:54.

Powered by vBulletin® Version 3.6.8
Copyright ©2000 - 2026, Jelsoft Enterprises Ltd.
Traducción al castellano por el equipo de moderadores del Club Delphi