Foros Club Delphi

Foros Club Delphi (https://www.clubdelphi.com/foros/index.php)
-   Varios (https://www.clubdelphi.com/foros/forumdisplay.php?f=11)
-   -   Ordenar datos en un DBGrid con click en cabecera (https://www.clubdelphi.com/foros/showthread.php?t=55949)

totote 02-05-2008 16:56:56

Ordenar datos en un DBGrid con click en cabecera
 
Bueno como vi que en la parte de trucos no funcionaba para componentes de dbExpress, le pregunte a google y me respondio XD.
Este código pertenece al siguiente sitio

Código que realiza el ordenamiento:
Código Delphi [-]
unit f_Varios;

interface

uses
      TypInfo, DBClient, DB;

function SortCustomClientDataSet(DataSet: TClientDataSet;const FieldName: String): Boolean;

implementation

function SortCustomClientDataSet(DataSet: TClientDataSet;const FieldName: String): Boolean;
var
  i: Integer;
  IndexDefs: TIndexDefs;
  IndexName: String;
  IndexOptions: TIndexOptions;
begin
  Result := False;
  if IsPublishedProp(DataSet, 'IndexDefs') then
    IndexDefs := GetObjectProp(DataSet, 'IndexDefs') as TIndexDefs
  else
    Exit;

  if IsPublishedProp(DataSet, 'IndexName') then
    IndexName := GetStrProp(DataSet, 'IndexName')
  else
    Exit;

  IndexDefs.Update;
  if DataSet.Fields.FindField(FieldName) = nil then Exit;
  if IndexName = FieldName + '__IdxA' then
  begin
    IndexName := FieldName + '__IdxD';
    IndexOptions := [ixDescending];
  end
  else
  begin
    IndexName := FieldName + '__IdxA';
    IndexOptions := [];
  end;
  for i := 0 to Pred(IndexDefs.Count) do
  begin
    if IndexDefs[i].Name = IndexName then
    begin
      Result := True;
      Break
    end; //if
  end; // for
  if not Result then
  begin
    DataSet.AddIndex(IndexName, FieldName,IndexOptions);
    Result := True;
  end; // if not
  SetStrProp(DataSet, 'IndexName', IndexName);
end;

Código para utilizar el ordenamiento:

Código Delphi [-]
procedure TForm1.DBGrid1TitleClick(Column: TColumn);
begin
  inherited;
  SortCustomClientDataset(ClientDataSet1,Column.FieldName);
end;


Saludos

BlueSteel 02-05-2008 17:33:41

Hola totote

si quieres ordenar por columna los datos que tienes un dBGrid, puedes utilizar el codigo que esta a continuación..

Debes utilizar el evento OnTitleClick del DBGrid...si pincho 1 vez me ordena por la columna en forma ascendente y si lo vuelvo a presionar me lo ordena en forma descendente... para controlar ese evento utilizo una variable ( Sw_1)


Código Delphi [-]
procedure DBGrid1TitleClick(Column: TColumn);
begin
     // Aqui pregunto si el titulo de la Columna es RUT
     If Column.Title.Caption='RUT' then
        Begin
             IBQ_Select.Close;
             IBQ_Select.SQL.Clear;
             If Sw_1 = 0 Then
                Begin
                     IBQ_Select.SQL.Add('Select * from "Proveedor" Order By "Pro_Rut" ASC');
                     Sw_1 := 1;
                End
             Else
                Begin
                     IBQ_Select.SQL.Add('Select * from "Proveedor" Order By "Pro_Rut" DESC');
                     Sw_1 := 0;
                End;
            IBQ_Select.Open;
        End;

bueno, el codigo anterior te ordena solo si pinchas en la columna con el titulo RUT, por lo que deberas agregar las demas columnas que necesites ordenar...

Espero que te funcione..

Salu2:p:D

roman 02-05-2008 18:19:37

Pero el código que pone totote está pensado específicamente para un ClientDataSet lo cual da la enorme ventaja de no tener que reconsultar a la base. El ordenamiento se hace en memoria, por lo cual es mucho más rápido. Además, el código es genérico; sirve para cualquier ClientDataSet sin importar el nombre de los campos ni la columna seleccionada.

Eso sí, creo que se puede simplificar un poco :p

Código Delphi [-]
procedure SortCDS(DataSet: TClientDataSet; Column: TColumn);
var
  IndexName: String;
  IndexOptions: TIndexOptions;

begin
  if DataSet.IndexName = Column.FieldName + '_IdxA' then
  begin
    IndexName := Column.FieldName + '_IdxD';
    IndexOptions := [ixDescending];
  end
  else
  begin
    IndexName := Column.FieldName + '_IdxA';
    IndexOptions := [];
  end;

  if DataSet.IndexDefs.IndexOf(IndexName) = -1 then
    DataSet.AddIndex(IndexName, Column.FieldName, IndexOptions);

  DataSet.IndexName := IndexName;
end;

// Saludos

totote 02-05-2008 18:34:25

Bien roman quedó bastante simplificado, igualmente yo lo postee así porque así lo encontre

Saludos

BlueSteel 02-05-2008 18:41:13

Cita:

Empezado por roman (Mensaje 283883)
Pero el código que pone totote está pensado específicamente para un ClientDataSet lo cual da la enorme ventaja de no tener que reconsultar a la base. El ordenamiento se hace en memoria, por lo cual es mucho más rápido. Además, el código es genérico; sirve para cualquier ClientDataSet sin importar el nombre de los campos ni la columna seleccionada.

Eso sí, creo que se puede simplificar un poco :p


Código Delphi [-]
procedure SortCDS(DataSet: TClientDataSet; Column: TColumn);
var
IndexName: String;
IndexOptions: TIndexOptions;

begin
if DataSet.IndexName = Column.FieldName + '_IdxA' then
begin
IndexName := Column.FieldName + '_IdxD';
IndexOptions := [ixDescending];
end
else
begin
IndexName := Column.FieldName + '_IdxA';
IndexOptions := [];
end;

if DataSet.IndexDefs.IndexOf(IndexName) = -1 then
DataSet.AddIndex(IndexName, Column.FieldName, [ixDescending]);

DataSet.IndexName := IndexName;
end;





// Saludos


Interesante el código.. esto me simplificaria varias lineas...

ahora donde se debe dejar este código y como se vincula a un dbGrid....??? para cuando pinchen los titulos se ordene....

Salu2:p:D

roman 02-05-2008 18:41:58

Tenía un error yo. La línea

Código Delphi [-]
DataSet.AddIndex(IndexName, Column.FieldName, [ixDescending]);

la cambié por

Código Delphi [-]
DataSet.AddIndex(IndexName, Column.FieldName, IndexOptions);

// Saludos

roman 02-05-2008 18:49:33

Cita:

Empezado por BlueSteel (Mensaje 283890)
ahora donde se debe dejar este código y como se vincula a un dbGrid....??? para cuando pinchen los titulos se ordene....

Pues como se indica en el código original, en el evento OnTitleClick del DBGrid:

Código Delphi [-]
procedure TForm1.DBGrid1TitleClick(Column: TColumn);
begin
  SortCDS(ClientDataSet1, Column);
end;

// Saludos

BlueSteel 02-05-2008 19:01:28

Cita:

Empezado por roman (Mensaje 283895)
Pues como se indica en el código original, en el evento OnTitleClick del DBGrid:


Código Delphi [-]
procedure TForm1.DBGrid1TitleClick(Column: TColumn);
begin
SortCDS(ClientDataSet1, Column);
end;





// Saludos


Ok...gracias...

lo estoy probando..aunque no con muy buenos resultados... pero seguiré intentando..

Salu2:p:D

totote 03-05-2008 00:16:41

El Código simplificado de Roman no lo pude probar, pero el código original el único error que le encontre fue que una vez utilizado el código, se desvincula el DBGrid y queda abierto el ClientDataSet, al volver a vincular el DBGrid me genera erro al querer encontrar las columnas con la cabezera modificada, despúes a mi me anduvo sin ningún problema.

Saludos :D

roman 03-05-2008 00:51:07

Cita:

Empezado por BlueSteel (Mensaje 283899)
lo estoy probando..aunque no con muy buenos resultados

Cita:

Empezado por totote (Mensaje 284006)
El Código simplificado de Roman no lo pude probar

¿O sea que no sirve? :(

// Saludos

totote 05-05-2008 04:49:58

No, no quise decir que no sirve sino que no lo he probado para ver como funciona realmete, para saber si anda o no hay que utilizarlo.

Saludos

BlueSteel 06-05-2008 01:18:54

me da error
 
Bueno.,... segui con las pruebas....

lo que hice fue crear una unidad nueva, pero me da error....

con el código que puso Roman cree esta unidad

Código Delphi [-]
unit Unit17;

interface

uses
    TypInfo, DBClient, DB;

procedure SortCDS(DataSet: TClientDataSet; Column: TColumn);
 
implementation
procedure SortCDS(DataSet: TClientDataSet; Column: TColumn);
var
  IndexName: String;
  IndexOptions: TIndexOptions;
begin
  if DataSet.IndexName = Column.FieldName + '_IdxA' then
  begin
    IndexName := Column.FieldName + '_IdxD';
    IndexOptions := [ixDescending];
  end
  else
  begin
    IndexName := Column.FieldName + '_IdxA';
    IndexOptions := [];
  end;
  if DataSet.IndexDefs.IndexOf(IndexName) = -1 then
    DataSet.AddIndex(IndexName, Column.FieldName, IndexOptions);
  DataSet.IndexName := IndexName;
end;
end.

pero me da el error de compilación

Unit17.pas(8): Undeclared identifier: 'TColumn'
Unit17.pas(18): Then expected but identifier 'FieldName' found

bueno y da otros más... quizas puede ser por que faltan algunas uses....

Salu2:p:D

BlueSteel 06-05-2008 01:25:51

Tambien probe con el codigo que dejo Totote.... si bien la funcion no me da error, cuando quiero ejecutar el codigo si me da error, pero puede ser por algo que este realizando mal...

Código Delphi [-]
procedure TForm1.DBGrid1TitleClick(Column: TColumn);
begin
  inherited;
  SortCustomClientDataset(ClientDataSet1,Column.FieldName);
end;

bueno, del codigo anterior, no se muy bien que debe ir en ClientDataSet1, puesto que lo he cambiado por el DBGrid, DataSourse y ADOQuery sin tener resultados positivos...

Salu2:p:D

roman 06-05-2008 01:29:52

Cita:

Empezado por BlueSteel (Mensaje 284408)
quizas puede ser por que faltan algunas uses....

¿Tú qué crees? :p

Supongo que te falta DBGrids y te sobra TypInfo.

// Saludos

BlueSteel 06-05-2008 22:46:02

Hola Roman

gracias... ya agrege/quite la unidad que me indicastes.... se compila, ya no da error...

estoy con el problema de poder utilizarla....

Segun como me indicastes, puse lo siguiente....
Código Delphi [-]
procedure TOCompra_Registro.DBGrid1TitleClick(Column: TColumn);
begin
     SortCDS(Datos.AQ_VOrden, Column);  // ADOQuery
    //Tambien probé con
    //SortCDS(Datos.DS_VOrden, Column);  // Datasourse
    //SortCDS(DBGrid1, Column);  // DBGrid
end;

pero me da error de incompatibilidad de tipos (TClientDataSet and TADOQuery / TClientDataSet and TDataSource / TClientDataSet and TDBGrid )

Bueno.. eso..

Salu2:p:D

roman 07-05-2008 06:13:57

Pero amigo Blue, estamos en distinto canal :D

Me cito a mi mismo

Cita:

Empezado por mimismo
Pero el código que pone totote está pensado específicamente para un ClientDataSet lo cual da la enorme ventaja de no tener que reconsultar a la base. El ordenamiento se hace en memoria, por lo cual es mucho más rápido. Además, el código es genérico; sirve para cualquier ClientDataSet sin importar el nombre de los campos ni la columna seleccionada.

Es decir, en todo momento asumí que este ordenamiento sólo serviría para un ClientDataSet

// Saludos

totote 20-05-2008 14:28:42

Bueno con respecto al Código original cuando se quería abrir el TClientDataSet generaba un error que no reconocia la columna, para solucionar ese problema lo que hice fue que al salir del formulario antes de cerrar el TClientDataSet llamo al siguiente procedimiento:

Código Delphi [-]
CleanCustomClientDataset(ClientDataSet1);

que sería esto solamente:

Código Delphi [-]
procedure CleanCustomClientDataSet(DataSet: TClientDataSet);
begin
  SetStrProp(DataSet, 'IndexName', '');
end;

Saludos.

NeoNew 04-03-2009 15:46:42

El siguinte codigo ordena con click en cualquier columna, pero necesito saber como se que una columna esta ordenada ASC o DESC para luego reordenarla.

Código Delphi [-]
procedure TForm.DBGrid1TitleClick(Column: TColumn);
{$J+}
 const PreviousColumnIndex : integer = -1;
{$J-}
begin
  if PreviousColumnIndex > -1 then
    begin
      DBGrid1.Columns[PreviousColumnIndex].title.Font.Style :=
      DBGrid1.Columns[PreviousColumnIndex].title.Font.Style - [fsBold];
    end;
    Column.title.Font.Style := Column.title.Font.Style + [fsBold];
    PreviousColumnIndex := Column.Index;
    ABSQuery1.Close;
    ABSQuery1.SQL.Text := 'SELECT * FROM Tabla ORDER BY '+ AnsiString(column.FieldName);
    ABSQuery1.RequestLive := True;
    ABSQuery1.Open;
end;

PD: ABSQuery = Query

jorge82 04-03-2009 17:23:35

Bueno esto es lo que yo uso para ordenar en un DBGrid utilizando ClientDataSets.

Código Delphi [-]
procedure TForm1.DBGridTitleClick(Column: TColumn);
var
  Campo: string;
begin
  try
    Campo := Column.FieldName;
    with Column.Grid.DataSource.DataSet as TClientDataSet do
      if IndexFieldNames <> Campo then
        IndexFieldNames := Campo // Ascendente
      else
      begin
        AddIndex(Campo, Campo, [], Campo); // Descendente
        IndexName := Campo;
      end;
  except // Para que no salte una excepción si la columna es un campo calculado.
  end;
end;

Esto es gracias a que el ClietDataSet permite crear índices en memoria en tiempo de ejecucíon (Sin crearlos en la base de datos, claro). Espero que a alguien le sirva.

Leviatan 31-05-2014 06:59:24

Muchas gracias por tu aporte jorge82. Lo probé y me ha funcionado perfectamente!

Gracias de vuelta!


La franja horaria es GMT +2. Ahora son las 14:29:03.

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