Foros Club Delphi

Foros Club Delphi (https://www.clubdelphi.com/foros/index.php)
-   C++ Builder (https://www.clubdelphi.com/foros/forumdisplay.php?f=13)
-   -   Ordenar TListView (https://www.clubdelphi.com/foros/showthread.php?t=85989)

Angel.Matilla 03-06-2014 17:38:40

Ordenar TListView
 
Con C++ Builder 6. Quiero ordenar un TListView en función de la etiqueta de la columna que pulse. Estoy usando este código:
Código:

void __fastcall TfSocios::FormCreate(TObject *Sender)
{
    LastSortedColumn = -1;
    Ascending = false;
}
//---------------------------------------------------------------------------

void __fastcall TfSocios::ListaColumnClick(TObject *Sender, TListColumn *Column)
{
    if (Column->Index == LastSortedColumn)
          Ascending = !Ascending;
    else
    {
          Ascending = true;
          LastSortedColumn = Column->Index;
    }
    static_cast<TListView>(Sender)->CustomSort(SortByColumn, Column->Index);
}
//---------------------------------------------------------------------------

Y esta es la función a la que llamo:
Código:

int  __stdcall SortByColumn(long Item1,long Item2, long Data)
{
    TListItem *item1    = reinterpret_cast<TListItem>(Item1);
    TListItem *item2    = reinterpret_cast<TListItem>(Item2);
    TListView *lv      = static_cast<TListView>(item1->ListView);
    TListColumn *lc    = static_cast<TListColumn>(lv->Columns->FindItemID(Data));
    bool bCampoNumerico = lc->Tag;
    int w;

    if (Data == 0)
    {
          w = !bCampoNumerico
              ? AnsiCompareText(item1->Caption, item2->Caption)
              : item1->Caption.ToIntDef(0) - item2->Caption.ToIntDef(0);
    }
    else
    {
          w = !bCampoNumerico
              ? AnsiCompareText(item1->SubItems->Strings[Data-1], item2->SubItems->Strings[Data-1])
              : item1->SubItems->Strings[Data-1].ToIntDef(0) - item2->SubItems->Strings[Data-1].ToIntDef(0);
    }
    return Ascending ? w : -w;
}

El problema es que da lo mismo las veces que pulse en la etiqueta de la columna: Sí me ordena por la columna seleccionda pero siempre en orden descendente; no hay manera de que lo haga al revés. Y es que no veo como usar esa variable Ascending en la que se indica la forma de ordenación.

ecfisa 03-06-2014 18:50:28

Hola Angel.Matilla.

Fijate si te sirve del modo que uso en este ejemplo:
Código:

...
int order;

int __stdcall CustomSortFn(long Item1, long Item2, long ParamSort)

{
  return CompareText(((TListItem *)Item1)->Caption,
                    ((TListItem *)Item2)->Caption) * order;
}

void __fastcall TForm1::ListView1ColumnClick(TObject *Sender,
      TListColumn *Column)
{
 order = (order == 1 ? -1 : 1) ;
 ListView1->CustomSort(CustomSortFn, 0);
}

Saludos :)

Angel.Matilla 03-06-2014 19:20:39

Gracias por la respuesta. Hay una cosa que me tiene desconcertado en la función CustomSortFn, igual que en el código que subí yo: En ambos casos se pasan tres parámetros; los dos primeros son evidentes ya que son los dos ítemes que hay que comparar pero el tercero (long ParamSort o long Data) ¿qué son o cómo se usa? Al llamar a la función no se declaran nada más que dos y eso es algo que no acabo de entender.

ecfisa 03-06-2014 19:50:59

Hola Angel.Matilla.

Lo podes usar para enviar el sentido del órden, tomando el ejemplo anterior quedaría:
Código:

int __stdcall CustomSortFn(long Item1, long Item2, long ParamSort)

{
  return CompareText(((TListItem *)Item1)->Caption,
                    ((TListItem *)Item2)->Caption) * ParamSort;
}

void __fastcall TForm1::ListView1ColumnClick(TObject *Sender,
      TListColumn *Column)
{
 static int order = 1;
 order = (order == 1 ? -1 : 1) ;
 ListView1->CustomSort(CustomSortFn, order);
}

Saludos :)

Angel.Matilla 04-06-2014 17:41:23

Muchas gracias por las explicaciones ecfisa.

Angel.Matilla 06-06-2014 12:44:48

Funciona a la perfección. Voy a abusar un poco más de tus conocimientos. Me he vuelto loco tratando de adaptar ese código para que pueda seleccionar por cualquiera de las columnas del ListView pero no he sido capaz de dar con ello. ¿Cómo podría hacerse?

ecfisa 06-06-2014 17:01:33

Hola Angel.Matilla.

Código:

int GColNo; // también podría ser privada al TForm... (int FColNo;)

int __stdcall CustomSortFn(long Item1, long Item2, long ParamSort)
{
  TListItem *it1 = reinterpret_cast<TListItem *>(Item1);
  TListItem *it2 = reinterpret_cast<TListItem *>(Item2);
  if (GColNo)
    return CompareText(it1->SubItems->Strings[GColNo-1],
                      it2->SubItems->Strings[GColNo-1]) * ParamSort;
  else
    return CompareText(it1->Caption, it2->Caption) * ParamSort;
}

void __fastcall TForm1::ListView1ColumnClick(TObject *Sender,
      TListColumn *Column)
{
 static int order = 1;

 GColNo = Column->Index;
 order = (order == 1 ? -1 : 1) ;
 ListView1->CustomSort(CustomSortFn, order);
}

Saludos :)

Angel.Matilla 06-06-2014 17:40:46

Muchas gracias. Juraría que lo que tengo es muy, muy parecico. Lo repasaré y ya te diré como me ha ido.

Angel.Matilla 07-06-2014 13:40:11

Me está ocurriendo algo muy curioso: Pulse la cabecera que pulse se ejecuta la función siempre como si el valor fuera 0, y he probado con el código que me has pasado, poniendo if (GColNo > 1) y con switch (GColNo). No lo entiendo

ecfisa 07-06-2014 16:23:00

1 Archivos Adjunto(s)
Hola Angel.Matilla.

Si, es extraño. Revisa los fuentes del demo adjunto que están funcionando correctamente.


Saludos :)

Angel.Matilla 09-06-2014 17:40:37

GRacias. Tu adjunto funciona a la perfección. Voy a ver que pasa en mi proyecto.

Angel.Matilla 09-06-2014 18:35:32

¡Resuleto! El problema estaba en DONDE estaba ubicando la función; la estaba llamando como función externa y en el "viaje" se despistaba el código. La he puesto en el formulario del TListView y funciona a la perfección. Muchísimas gracias ecfisa.

ecfisa 09-06-2014 18:42:44

Me alegro que lo resolvieras ^\||/

Saludos :)


La franja horaria es GMT +2. Ahora son las 19:26:08.

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