[delphi]_dicas sobre o componente dbgrid.pdf

7
07/08/13 Dicas sobre o componente DBGrid do Delphi | Diego Garcia drgarcia1986.wordpress.com/2013/01/17/dicas-sobre-o-componente-dbgrid-do-delphi/ 1/7 Dicas sobre o componente DBGrid do Delphi Publicado em 17/01/2013 O Dbgrid talvez seja um dos componentes mais utilizados no dia a dia de um desenvolvedor delphi, principalmente em soluções comerciais, isso graças ao fato de que o uso deste componente seja definitivamente a maneira mais simples e mais rápida de apresentar dados de um dataSet para o usuário, seja esse dataSet o resultado de uma pesquisa em um banco de dados, registros temporários, etc. Na grande realidade o conceito de grid está presente em qualquer ambiente de desenvolvimento. Neste post eu resolvi juntar algumas dicas simples e práticas para melhorar a utilização deste componente. Para melhor demonstrar os resultados dos exemplos, criei um projeto teste com dados fictícios em um ClienteDataSet, porem, os exemplos que fiz são quase que 100% independentes do tipo de dataSet utilizado. Fazer linha zebrada: vamos usar a lógica mais utilizada para zebrar linhas em um grid, verificar se o numero do registro atual do dataSet é impar ou par, veja que não estou falando do valor de algum campo do dataSet, mas sim o numero da linha dentro do dataSet. Para recuperar essa informação, nos dataSet temos a propriedadeRecNo que consiste no numero do registro ativo no dataSet e para saber se esse numero é impar ou par, basta usar o método Odd que retornar true se um numero é impar e false se esse for par. Para implementar essa rotina, iremos utilizar o eventoOnDrawColumnCell do DbGrid que consiste no evento em que os dados são “desenhados” no grid. Note que para customizar a visualização do meu grid, eu utilizei a propriedade Canvas, é nesta propriedade que ficam as configurações de tela do grid. Dentro da propriedade canvas, eu tenho a propriedade Brush, que é utilizada para pintar o fundo de uma linha no grid. O resultado deste exemplo ficaria desta forma 1 2 3 4 5 6 7 8 9 10 11 12 13 14 procedure TForm1 . DBGrid1DrawColumnCell(Sender: TObject; const Rect: TRec DataCol: Integer ; Column: TColumn; State: TGridDrawState); begin with DBGrid1 do begin if Odd( DataSource . DataSet . RecNo) then Canvas . Brush . Color := clSilver else Canvas . Brush . Color := clMoneyGreen; Canvas . FillRect(Rect); DefaultDrawColumnCell(Rect,DataCol,Column,State); end ; end ;

Upload: lucio-mathias

Post on 28-Oct-2015

531 views

Category:

Documents


3 download

TRANSCRIPT

Page 1: [Delphi]_Dicas sobre o componente DBGrid.pdf

07/08/13 Dicas sobre o componente DBGrid do Delphi | Diego Garcia

drgarcia1986.wordpress.com/2013/01/17/dicas-sobre-o-componente-dbgrid-do-delphi/ 1/7

Dicas sobre o componente DBGrid do DelphiPublicado em 17/01/2013

O Dbgrid talvez seja um dos componentes mais utilizados no dia a dia de um desenvolvedor

delphi, principalmente em soluções comerciais, isso graças ao fato de que o uso deste

componente seja definitivamente a maneira mais simples e mais rápida de apresentar dados

de um dataSet para o usuário, seja esse dataSet o resultado de uma pesquisa em um banco de

dados, registros temporários, etc. Na grande realidade o conceito de grid está presente em

qualquer ambiente de desenvolvimento.

Neste post eu resolvi juntar algumas dicas simples e práticas para melhorar a utilização deste

componente. Para melhor demonstrar os resultados dos exemplos, criei um projeto teste com

dados fictícios em um ClienteDataSet, porem, os exemplos que fiz são quase que 100%

independentes do tipo de dataSet utilizado.

Fazer linha zebrada: vamos usar a lógica mais utilizada para zebrar linhas em um grid,

verificar se o numero do registro atual do dataSet é impar ou par, veja que não estou

falando do valor de algum campo do dataSet, mas sim o numero da linha dentro do

dataSet. Para recuperar essa informação, nos dataSet temos a propriedadeRecNo que

consiste no numero do registro ativo no dataSet e para saber se esse numero é impar ou

par, basta usar o método Odd que retornar true se um numero é impar e false se esse for

par. Para implementar essa rotina, iremos utilizar o eventoOnDrawColumnCell do DbGrid

que consiste no evento em que os dados são “desenhados” no grid.

Note que para customizar a visualização do meu grid, eu utilizei a propriedade Canvas, é

nesta propriedade que ficam as configurações de tela do grid. Dentro da propriedade canvas,

eu tenho a propriedade Brush, que é utilizada para pintar o fundo de uma linha no grid. O

resultado deste exemplo ficaria desta forma

1234567891011121314

procedure TForm1.DBGrid1DrawColumnCell(Sender: TObject; const Rect: TRect; DataCol: Integer; Column: TColumn; State: TGridDrawState);begin

with DBGrid1 do begin

if Odd( DataSource.DataSet.RecNo) then Canvas.Brush.Color := clSilver else Canvas.Brush.Color := clMoneyGreen;

Canvas.FillRect(Rect); DefaultDrawColumnCell(Rect,DataCol,Column,State); end;end;

Page 2: [Delphi]_Dicas sobre o componente DBGrid.pdf

07/08/13 Dicas sobre o componente DBGrid do Delphi | Diego Garcia

drgarcia1986.wordpress.com/2013/01/17/dicas-sobre-o-componente-dbgrid-do-delphi/ 2/7

Destacar linhas: Muitas vezes precisamos dar algum destaque visual para

determinados registros dependendo de alguma condição, para isso, podemos alterar

dinamicamente a formatação de fonte ou até mesmo a cor de fundo de uma linha do

DBGrid. Seguindo os dados que criei para os exemplos faremos com que, os registros que

tiverem um valor maior do que 2500 no campo salario fiquem com a linha vermelha

quando selecionados e os não selecionados fiquem com a fonte vermelha e em negrito.

Comparando com o exemplo anterior não temos muitas diferenças, a não ser pela verificação

gdSelected in State, caso esta verificação resulte em true significa que neste momento o

DBGrid está desenhando a linha selecionada. Neste o exemplo, o resultado ficaria desta forma

Destacar uma célula e uma coluna: Este exemplo, não chega a ser muito diferente

do anterior, por isso, mantive a mesma lógica, a coluna referente ao camposalario ficará

12345678910111213141516171819

procedure TForm1.DBGrid1DrawColumnCell(Sender: TObject; const Rect: TRect; DataCol: Integer; Column: TColumn; State: TGridDrawState);begin

with DBGrid1 do begin

if DataSource.DataSet.FieldByName('salario').AsFloat > 2500 then begin

if (gdSelected in State) then Canvas.Brush.Color := clRed else begin Canvas.Font.Style := [fsBold]; Canvas.Font.Color := clRed; end end; Canvas.FillRect(Rect); DefaultDrawColumnCell(Rect,DataCol,Column,State); end;end;

Page 3: [Delphi]_Dicas sobre o componente DBGrid.pdf

07/08/13 Dicas sobre o componente DBGrid do Delphi | Diego Garcia

drgarcia1986.wordpress.com/2013/01/17/dicas-sobre-o-componente-dbgrid-do-delphi/ 3/7

com o fundo cinza, porem, caso algum registro tenha uma valor neste campo maior do que

2500, a célula ficará com o fundo vermelho e a fonte amarela.

Talvez a diferença mais importante entre este exemplo e o anterior é a verificação feita pela

coluna, ou seja, a manipulação do canvas é feita somente quando a coluna salario está

sendo desenhada. Rodando esse exemplo em nossa base de estudo, teríamos o seguinte

resultado

Inserir um checkbox em um coluna: Esse exemplo foi particularmente

muito útil para mim no meu dia a dia, tanto que quando pensei em fazer esse post, foi o

primeiro exemplo que separei para demonstrar. Ainda no evento OnDrawColumnCell,

assim como no exemplo anterior, primeiramente precisamos saber se estamos

desenhando a coluna que recebera o checkBox para, ai sim, inserir o componente no grid.

123456789101112131415161718

procedure TfrmPrincipal.DBGrid1DrawColumnCell(Sender: TObject; const Rect: TRect; DataCol: Integer; Column: TColumn; State: TGridDrawState);begin

with DBGrid1 do begin

if AnsiLowerCase(Column.FieldName) = 'salario' then begin Canvas.Brush.Color := clSilver;

if Column.Field.AsFloat > 2500 then begin Canvas.Brush.Color := clRed; Canvas.Font.Color := clYellow; end; end; Canvas.FillRect(Rect); DefaultDrawColumnCell(Rect,DataCol,Column,State); end;end;

12345678

procedure TForm1.DBGrid1DrawColumnCell(Sender: TObject; const Rect: TRect; DataCol: Integer; Column: TColumn; State: TGridDrawState);const

IS_CHECK : Array[Boolean] of Integer = (DFCS_BUTTONCHECK, DFCS_BUTTONCHECK var Check : Integer; R : TRect;begin

with DBGrid1 do

Page 4: [Delphi]_Dicas sobre o componente DBGrid.pdf

07/08/13 Dicas sobre o componente DBGrid do Delphi | Diego Garcia

drgarcia1986.wordpress.com/2013/01/17/dicas-sobre-o-componente-dbgrid-do-delphi/ 4/7

O código acima alem de inserir o checkBox no campo selecionado já define se este checkBox

vai estar marcado ou desmarcado, de acordo com o valor do campo em questão, através da

variável Check, o resultado deste exemplo ficaria desta forma

Para deixar um pouco mais prático o uso do checkBox no DBgrid, podemos fazer uma rotina

para marcar ou desmarcar o componente quando a célula que ele está seja clicada

Inserir uma imagem em uma coluna: Eu particularmente usei pouco esse recurso

mas todas as vezes que usei gostei bastante do resultado, a parte boa é que é bem simples

de fazer. Como auxilio vamos utilizar um componente TImageList para poder armazenar

as imagens que iremos utilizar. Trabalhando com a ideia do camposelecionado, vamos

inserir duas imagens no TImageList e já deixar com que a imagem referente ao

valor False do campo fique com o índice zero enquanto que a referente ao valor True fique

91011121314151617181920

begin

if AnsiLowerCase(Column.FieldName) = 'selecionado' then begin Canvas.FillRect(Rect); Check := IS_CHECK[Column.Field.AsBoolean]; R := Rect; InflateRect(R,-2,-2); //aqui manipula o tamanho do checkBox DrawFrameControl(Canvas.Handle,rect,DFC_BUTTON,Check) end; end;end;

123456789101112

procedure TForm1.DBGrid1CellClick(Column: TColumn);begin

if Column.Field.FieldName = AnsiLowerCase('selecionado') then begin

with DBGrid1.DataSource.DataSet do begin edit;

FieldByName('selecionado').Value := not FieldByName('selecionado').AsBoolean; Post; end; end;end;

Page 5: [Delphi]_Dicas sobre o componente DBGrid.pdf

07/08/13 Dicas sobre o componente DBGrid do Delphi | Diego Garcia

drgarcia1986.wordpress.com/2013/01/17/dicas-sobre-o-componente-dbgrid-do-delphi/ 5/7

com o índice 1

Agora basta desenhar as imagens no DBGrid de acordo com a coluna e o valor da coluna.

Simples não? Até mais simples do que o checkBox, apesar de nem sempre deixar o visual

mais profissional.

Utilizar um ComboBox em uma coluna: A técnica de utilizar um ComboBox em um

grid é feita de uma forma um pouco diferente dos exemplos anteriores, dentro

dasColumns do Dbgrid existe a propriedade PickList que consiste em um objeto do

123456789101112

procedure TForm1.DBGrid1DrawColumnCell(Sender: TObject; const Rect: TRect; DataCol: Integer; Column: TColumn; State: TGridDrawState);begin

with DBGrid1 do begin

if AnsiLowerCase(Column.FieldName) = 'selecionado' then begin Canvas.FillRect(Rect); ImageList1.Draw(Canvas,Rect.Left+10,Rect.Top+1,Ord(Column.Field.AsBoolean)); end; end;end;

Page 6: [Delphi]_Dicas sobre o componente DBGrid.pdf

07/08/13 Dicas sobre o componente DBGrid do Delphi | Diego Garcia

drgarcia1986.wordpress.com/2013/01/17/dicas-sobre-o-componente-dbgrid-do-delphi/ 6/7

tipoTStrings e é utilizado exatamente para dar esse efeito do combo dentro de uma célula

do grid. Então para demonstrar a utilização desta propriedade, dentro do meu método de

carregar os dados, eu coloquei o seguinte trecho de código:

Obviamente este é apenas um exemplo didático, em uma situação real poderíamos carregar

esta propriedade com valores vindos de uma tabela de validação por exemplo. O código acima

daria o seguinte efeito:

Ordenar dinamicamente pela coluna clicada pelo usuário: Por experiencia eu

digo que a ordenação dos dados em um DBgrid é uma das coisas mais importantes na hora

de apresentar dados para um usuário, mas é normal surgir a pergunta, como saber por

qual campo ordenar os dados? Simples, permita que o usuário escolha por qual campo ele

quer fazer a ordenação. Pode parecer que não, mas é algo simples, neste exemplo faremos

com que quando o usuário clique no titulo de uma coluna no DBgrid, este seja ordenado

pelo campo desta coluna. Para deixar mais intuitivo para o usuário, vamos mudar o icone

do mouse quando este estivar passando pelo titulo dos campos no DBGrid, através do

método OnMouseMove

12345678

with Dbgrid1.Columns[2].PickList do //coluna referente ao cargobegin Clear; Add('GERENTE'); Add('REPRESENTANTE'); Add('ENCANADOR'); Add('VENDEDOR');end;

1234567891011

procedure TForm1.DBGrid1MouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);var mousePt: TGridcoord;begin mousePt := DbGrid1.MouseCoord(x,y);

if mousePt.y = 0 then Screen.Cursor := crHandPoint else Screen.Cursor := crDefault;end;

Page 7: [Delphi]_Dicas sobre o componente DBGrid.pdf

07/08/13 Dicas sobre o componente DBGrid do Delphi | Diego Garcia

drgarcia1986.wordpress.com/2013/01/17/dicas-sobre-o-componente-dbgrid-do-delphi/ 7/7

Esse método MouseCoord do DBgrid, retorna dentro um record de TGridcoord, em qual linha

(Y) e em qual coluna (X) do grid o cursor do mouse está, por exemplo se você estiver com o

cursor do mouse na segunda linha e terceira coluna, teríamos os seguintes valores no

TGridcoord.Y e TGridcoord.X

Agora vamos efetivamente fazer a ordenação dos dados. Para deixar um pouco mais visual,

vamos também deixar em negrito o titulo da coluna em que o DBgrid está ordenado. A

ordenação dos dados com clientDataSet fica fácil graças a propriedade IndexFieldNamesque

define por quais campos o clientDataSet será indexado. Sendo assim no métodoOnTitleClick,

basta colocar o seguinte código:

Seguindo este exemplo, ao clicar no titulo da coluna nome o resultado seria este

Talvez este seja o único exemplo que faça com as dicas deste post não sejam 100%

compatíveis com qualquer dataSet, pois utilizamos um método próprio de ClientDataSets,

porem isso não significa que não seja possível fazer este exemplo com outros tipos de

dataSets, basta fazer uma ou outra adaptação.

12

Y = 2;X = 3;

123456789

procedure TForm1.DBGrid1TitleClick(Column: TColumn);var I: Integer;begin

for I := 0 to DBGrid1.Columns.Count - 1 do DBGrid1.Columns[i].Title.Font.Style := []; TClientDataSet(DBGrid1.DataSource.DataSet).IndexFieldNames := Column.FieldName; Column.Title.Font.Style := [fsBold];end;