PDA

Ver la Versión Completa : Buscar elemento en listbox


mblascog
05-05-2016, 23:43:13
Buenas,
Estoy intentando encontrar la manera que según el contenido de un edit.txt se posicione el cursor en un listbox.
He hecho lo siguiente:

procedure Tpform.buscaChange(Sender: TObject);
begin
if Lista.Items.IndexOf(busca.text) > 0 then
Lista.ItemIndex := Lista.Items.IndexOf(busca.text);
end;

Pero este código posiciona el cursor siempre que la coincidencia sea exacta, y a mi me gustaría que se posicionara cuando coincida el inicio del elemento del listbox, es dir, si en el edit.txt escribo 'ab' se posicione al primer elemento que empieze por ab.
Estoy leyendo que no es posible. Si no es posible, hay algún componente que lo permita?

Gracias

AgustinOrtu
06-05-2016, 00:39:05
En donde dice que no es posible?

Lo podes implementar "a mano", o podes buscar por "ComboBox incremental search".

En Delphi 7 creo que no esta implementado, pero en realidad el que lo implementa es el control ComboBox de Windows que la VCL envuelve, con enviar un mensaje usando la API de Windows lo podes lograr

La otra forma es implementarlo uno mismo

Debes recorrer los strings contenidos en tu combo, comparar cada uno con la cadena de texto que esta ingresada en el combo en ese momento, y si hay coincidencia parcial, poner ese elemento como seleccionado y cortar el bucle

uses
StrUtils;

procedure TForm1.ComboBox1Change(Sender: TObject);
var
I: Integer;
AText, s: string;
begin
AText := ComboBox1.Text;

if AText = EmptyStr then
Exit;

for I := 0 to ComboBox1.Items.Count - 1 do
begin
s := ComboBox1.Items[I];
if StartsText(AText, s) then
begin
ComboBox1.ItemIndex := I;
ComboBox1.SelStart := Length(AText);
ComboBox1.SelLength := Length(s) - Length(AText);
Break;
end;
end;
end;

Creo que este es un inicio

Edito: Perdon, lei mal, hablas de TListBox, pero creo que el concepto es el mismo

mblascog
06-05-2016, 09:04:06
Gracias AgustinOrtu. Creo que defiere un poco entre el ComboBox y el ListBox. SeltStart y SelLength no están implementadas en ListBox.
Había pensado en la implementación manual, y voy a hacerlo ahora, pero me da la sensación que debe ser lento, pues además de buscar si por el contenido del edit empieza algún elemento del listbox (ordenado), tienes que comprobar cuando se haya pasado, para no hacer todo el bucle

Neftali [Germán.Estévez]
06-05-2016, 09:51:07
Con esto te debería valer:


var
i, j: Integer;
begin
j := -1;
for i := 0 to (ListBox1.Count - 1) do begin
if AnsiStrLIComp(PChar(ListBox1.Items[i]), PChar(Edit1.Text), Length(Edit1.Text))=0 then begin
j := i;
Break;
end;
end;
ListBox1.ItemIndex := j;


Te selecciona el primero que coincida o no te selecciona ninguno si no hay elemento coincidente.

Si cambias AnsiStrLIComp (case-insensitive) por AnsiStrLComp (case-sensitive) conseguirás que distinga o no por may/min.

mblascog
06-05-2016, 10:10:40
Muchas gracias, funciona perfecto, aunque para optimizarlo, ya que la lista contiene muchos ítems, está bien controlar que cuando se ha pasado de largo salga del bucle

mblascog
06-05-2016, 11:52:51
Para optimizar había pensado con este if:

if copy(Listbox1.Items[i], 1, length(edit1.text) > edit1.text then
break

Pero no funciona, pues Ló es más grande que Lu, con esto quiero decir que, si por ejemplo busco Lucena no lo encuentra, dado que antes encuentra López y al ser mayor, sale del bucle

Neftali [Germán.Estévez]
06-05-2016, 13:41:54
Muchas gracias, funciona perfecto, aunque para optimizarlo, ya que la lista contiene muchos ítems, está bien controlar que cuando se ha pasado de largo salga del bucle

Creo que he puesto el break dentro del bucle.
:cool: