sexta-feira, 7 de dezembro de 2007

Dica Delphi: Ordenando StringGrid clicando no título - crescente e decrescente

Essa dica é pra galera que programa em Delphi. Quem já se arriscou em usar o StringGrid. Ele não tem recurso nativo para ordenar os campos, clicando no título da coluna. Alias, clicando em seu titulo, nem realiza o movimento de 'clicado', como em outros componentes, tais como o DBGrid, por exemplo.
Por isto, com o auxilio de algumas soluções na internet, montei algumas funções, que ao clicar no título da coluna, ele ordena em ordem crescente; clicando novamente, em decrescente, além de simular o efeito de 'clicado'! Essa solução foi inspirada em soluções de Cristiano Kliemann (http://www.cristianok.hpg.com.br) e no site http://www.clubdelphi.com/foros/showthread.php?t=21456.

  • Na seção type:

type
TSGSortCompareProc = function(SG: TStringGrid; Col, Row1, Row2: Integer): Integer;

  • Crie as seguintes funções:

procedure SGQuickSort(SG: TStringGrid; L, R: Integer;
SCompare: TSGSortCompareProc; Col: Integer);
var
I, J, C, M: Integer;
begin
repeat
I := L;
J := R;
M := (L + R) shr 1;
repeat
while SCompare(SG, Col, I, M) < 0 do
Inc(I);
while SCompare(SG, Col, J, M) > 0 do
Dec(J);
if I <= J then
begin
for C := 0 to SG.ColCount - 1 do
SG.Cols[C].Exchange(I, J);
if I = M then
M := J
else
if J = M then M := I;
Inc(I);
Dec(J);
end;
until I > J;
if L < J then
SGQuickSort(SG, L, J, SCompare, Col);
L := I;
until I >= R;
end;



function ComparaString(SG: TStringGrid; Col, Row1, Row2: Integer): Integer;
begin
Result := AnsiCompareText(SG.Cells[Col, Row1], SG.Cells[Col, Row2]);
end;

function ComparaStringInvertido(SG: TStringGrid; Col, Row1, Row2: Integer): Integer;
begin
Result := AnsiCompareText(SG.Cells[Col, Row2], SG.Cells[Col, Row1]);
end;

function ComparaNumeros(SG: TStringGrid; Col, Row1, Row2: Integer): Integer;
var a,b : real;
begin
try a := StrToFloat(SG.Cells[col,row1]); except a := 0; end;
try b := StrToFloat(SG.Cells[col,row2]); except b := 0; end;
Result := Round( (a - b)*100000 );
end;

function ComparaNumerosInvertido(SG: TStringGrid; Col, Row1, Row2: Integer): Integer;
var a,b : real;
begin
try a := StrToFloat(SG.Cells[col,row1]); except a := 0; end;
try b := StrToFloat(SG.Cells[col,row2]); except b := 0; end;
Result := Round( (b - a)*100000 );
end;

function ComparaData(SG: TStringGrid; Col, Row1, Row2: Integer): Integer;
var a, b: TDate;
begin
try a:=StrToDate(SG.Cells[Col,Row1]); except a := Date(); end;
try b:=StrToDate(SG.Cells[Col,Row2]); except b := Date(); end;
Result := round(a - b ) ;
end;

function ComparaDataInvertido(SG: TStringGrid; Col, Row1, Row2: Integer): Integer;
var a, b: TDate;
begin
try a:=StrToDate(SG.Cells[Col,Row1]); except a := Date(); end;
try b:=StrToDate(SG.Cells[Col,Row2]); except b := Date(); end;
Result := round(b - a ) ;

end;

procedure StrGridSort(SG: TStringGrid; Col: Integer; tipo: integer; decrescente: boolean; total: boolean);
var linhas: integer;
begin
if total then
linhas := SG.RowCount - 2
else
linhas := SG.RowCount - 1;
if (tipo=1) then //caso for numerico
begin
if decrescente then //Comeca pela linha 2 porque a Linha 1 é usada para definir o tipo
SGQuickSort(SG, 2, linhas, @ComparaNumerosInvertido, Col)
else
SGQuickSort(SG, 2, linhas, @ComparaNumeros, Col);
end
else if (tipo=2) then//caso for string
begin
if decrescente then
SGQuickSort(SG, 2, linhas, @ComparaStringInvertido, Col)
else
SGQuickSort(SG, 2, linhas, @ComparaString, Col);
end
else //caso for data
if decrescente then
SGQuickSort(SG, 2, linhas, @ComparaDataInvertido, Col)
else
SGQuickSort(SG, 2, linhas, @ComparaData, Col);
end;

  • PARA UTILIZAR AS FUNÇÕES:
Declare as seguintes variaveis na seção private do form:
_cod, GiRow, GiCol, coluna : integer;
GCelda : TRect;

Para ordenar a StringGrid, utiliza-se a seguinte procedure:

StrGridSort(SG: TStringGrid; Col: Integer; tipo: integer; decrescente: boolean; total: boolean);

Onde:
SG: O Nome da StringGrid
Col: A coluna que irá ser utilizada como refetencia
tipo: 1: Conteúdo numérico; 2: String; 3: Data
decrescente: True: ordena em ordem decrescente. False: Ordem Crescente
Total: True: Não ordena a ultima linha. False: Ordena a ultima linha

Ao criar a StringGrid, a linha 1 é utilizada para definir o tipo do campo.
Por exemplo, ao criar uma StringGrid com 3 campos: Codigo(numerico), Nome(String),Data_Emissao(Data),
usa-se o seguinte codigo:

grid.Cells[0,1] := 'N';
grid.Cells[1,1] := 'S';
grid.Cells[2,1] := 'D';
grid.RowHeights[1]:=0;

  • No Evento OnMouseDown do StringGrid:

procedure StringGrid1MouseDown(Sender: TObject;
Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
Var
Valor :String;
tipo : integer;
LGcCoord: TGridCoord; //Define as coordenadas do mouse na grid
begin

LGcCoord := TCustomGrid(StringGrid1).MouseCoord(x,y);
GiCol := LGcCoord.X;
GiRow := LGcCoord.Y;
if (GiRow = 0) And (Button = mbleft) And (GiCol <> -1) then
Begin
with StringGrid1 do
Begin
GCelda := CellRect(GiCol,0);
Valor := Cells[GiCol, 0];
Canvas.Font := Font;
Canvas.Brush.Color := clInactiveCaptionText;
Canvas.FillRect(GCelda);
Canvas.TextRect(GCelda, GCelda.Left + 2, GCelda.Top + 2, Valor);
DrawEdge(Canvas.Handle, GCelda, 10, 2 or 4 or 8);
DrawEdge(Canvas.Handle, GCelda, 2 or 4, 1);
End;

if (StringGrid1.Cells[GiCol,1]='N') then
tipo := 1
else
if (Grid.Cells[GiCol,1]='S') then
tipo := 2
else
tipo := 3;

if ( (GiCol > 0) and (GiRow < (Grid.RowCount-1)) ) then begin if (GiCol=coluna) then begin StrGridSort(StringGrid1,GiCol,tipo, true, false); coluna := -1; end else begin StrGridSort(StringGrid1,GiCol,tipo, false,false); coluna := GiCol; end; end; end; end;
  • No evento OnMouseUp:
procedure StringGrid1MouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); Var Valor :String; begin if (GiRow = 0) And (Button = mbleft) And (GiCol <> -1) then
Begin
with StringGrid1 do
Begin
Valor := Cells[Gicol, 0];
Canvas.Font := Font;
Canvas.Brush.Color := clInactiveCaptionText;
Canvas.FillRect(GCelda);
Canvas.TextRect(GCelda, GCelda.Left + 2, GCelda.Top + 2, Valor);
DrawEdge(Canvas.Handle, GCelda, 4, 4 or 8);
DrawEdge(Canvas.Handle, GCelda, 4, 1 or 2);
GCelda := StringGrid1.CellRect(1, 1);
End;
End;

end;

6 comentários:

Unknown disse...

Nossa, era exatamente o que eu estava precisando...espero que funcione direitinho!!! Muito obrigada!!! :)

Unknown disse...

Meu, me ajudou mto mesmo!!

eu achei q nao ia encontrar isso na net, e ia ter q perder moh tempo criando isso...

Obrigado!!

Unknown disse...

muito bom

obrigado!!!

Unknown disse...

Me ajudou bastante, obrigado.

Maryellen Rezende disse...
Este comentário foi removido pelo autor.
André Ferreira disse...

Fábio, sou iniciante em delphi. Quero ordenar meu stringgrid de acordo com a segunda coluna.. integrei o seu código ao meu, sem erros na hora de compilar. mas nao acontece nada. nen clicando no stringrid, nen fazendo um botao chamando a funçao de ordenar o SG.

me da um help?