Não é a linguagem de programação que define o programador, mas sim sua lógica

Dicas sobre o componente DBGrid do Delphi


O TDBGrid talvez seja um dos componentes mais utilizados no dia a dia de um desenvolvedor Delphi.
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 :Temos que verificar se o numero do registro atual do DataSet é impar ou par, nos dataSet temos a propriedade RecNo 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 evento OnDrawColumnCell do TDbGrid que consiste no evento em que os dados são “desenhados” no grid.
procedure TForm1.dbGridTesteDrawColumnCell(Sender: TObject; const Rect: TRect;
  DataCol: Integer; Column: TColumn; State: TGridDrawState);
begin
  if Odd(ClientDataSet1.RecNo) then
    dbGridTeste.Canvas.Brush.Color := clWindow
  else
    dbGridTeste.Canvas.Brush.Color := clMoneyGreen;
  dbGridTeste.Canvas.FillRect(Rect);
  dbGridTeste.DefaultDrawColumnCell(Rect, DataCol, Column, State);
end;
Utilizamos a propriedade Canvas, dentro de canvas a propriedade Brush, que é utilizada para pintar o fundo de uma linha no grid. O resultado deste exemplo ficaria desta forma.

Destacar linhas: Nesse exemplo vamos destacar as linhas com da fonte vermelha e em negrito nos que tiverem o salario menor de 1900,00.
procedure TFSistema.dbGridTesteDrawColumnCell(Sender: TObject; const Rect: TRect;
  DataCol: Integer; Column: TColumn; State: TGridDrawState);
begin
  if ClientDataSet.FieldByName('VALOR').AsFloat <= 1900 then  begin
    if (gdSelected in State) then
      dbGridTeste.Canvas.Brush.Color := clRed
    else begin
      dbGridTeste.Canvas.Font.Style := [fsBold];
      dbGridTeste.Canvas.Font.Color := clRed;
    end;
    dbGridTeste.Canvas.FillRect(Rect);
    dbGridTeste.DefaultDrawColumnCell(Rect,DataCol,Column,State);
  end;
end;
Agora estamos utilizando "gdSelected in State", se resultar true significa que esta posicionado na linha do TDBGrid.


Destacar uma célula e uma coluna: Agora vamos fazer por célula, quando o valor for menor que 1900,00 a célula vai ficar vermelha e a letra branca e se maior a célula ficara verde. Algo semelhante ao exemplo anterior
procedure TFSistema.dbGridTesteDrawColumnCell(Sender: TObject; const Rect: TRect;
  DataCol: Integer; Column: TColumn; State: TGridDrawState);
begin
  if Column.FieldName = 'VALOR' then begin
    if Column.Field.AsFloat <= 1900 then begin
      dbGridTeste.Canvas.Brush.Color := clRed;
      dbGridTeste.Canvas.Font.Color := clWhite;
    end else
      dbGridTeste.Canvas.Brush.Color := clTeal;
    dbGridTeste.Canvas.FillRect(Rect);
    dbGridTeste.DefaultDrawColumnCell(Rect,DataCol,Column,State);
  end;
end;


Inserir um checkbox em um coluna:Já fiz um post com apenas esse exemplo, e um dos que mais utilizo. Vamos inserir o checkBox com isso vamos usar um campo integer o SEL e nele vamos jogar 1 ou 0 em caso de 0 esta desmarcado e 1 marcado, conseguimos fazer isto através da variável Check.
procedure TFSistema.dbGridTesteDrawColumnCell(Sender: TObject; const Rect: TRect;
  DataCol: Integer; Column: TColumn; State: TGridDrawState);
 var
  R: TRect;
  Check: integer;
begin
  if (Column.Index = 0) then begin
    if (ClientDataSet.FieldByName('SEL').Value = 0) then
      Check := DFCS_BUTTONCHECK or DFCS_CHECKED
    else
      Check := DFCS_BUTTONCHECK;
    dbGridTeste.Canvas.FillRect(Rect);
    R := Rect;
    InflateRect(R, -2, -2);
    DrawFrameControl(dbGridTeste.Canvas.Handle, R, DFC_BUTTON, Check);
  end;
end;

 
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
procedure TFSistema.dbGridTesteDblClick(Sender: TObject);
begin
  ClientDataSet.Edit;
  ClientDataSetSEL.Value := IfThen(ClientDataSetSEL.Value = 1, 0, 1);
  ClientDataSet.Post;
end;

Inserir uma imagem em uma coluna:Vamos utilizar o componente TImageList para poder armazenar as imagens. Com a mesma ideia do marcar e desmarcar do CheckBox.

Já no TDBGrid vai o código abaixo: 
procedure TFSistema.dbGridTesteDrawColumnCell(Sender: TObject; const Rect: TRect;
  DataCol: Integer; Column: TColumn; State: TGridDrawState);
var
  lIcon: TBitmap;
begin
  if (Column.Index = 0) then begin
    lIcon := TBitmap.Create;
    lIcon.Transparent := True;
    ImageList1.GetBitmap(ifthen(ClientDataSetSEL.Value = 1, 1, 0), lIcon);
    try
      dbGridTeste.Canvas.FillRect(Rect);
      dbGridTeste.Canvas.Draw(Round((Rect.Left + Rect.Right - lIcon.Width) / 2), Rect.Top, lIcon);
    finally
      FreeAndNIl(lIcon);
    end;
  end;
end;


Utilizar um ComboBox em uma coluna: Dentro dasColumns do Dbgrid existe a propriedade PickList que tem o objeto do tipo TStrings 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 método de carregar os dados, vamos colocar o seguinte trecho de código:
procedure TFSistema.DoCreate;
begin
  with dbGridTeste.Columns[2].PickList do begin
    Clear;
    Add('GERENTE');
    Add('REPRESENTANTE');
    Add('ENCANADOR');
    Add('VENDEDOR');
  end;
end; 


Ordenar dinamicamente pela coluna clicada pelo usuário: Vamos fazer uma ordenação que o usuário escolha por qual campo ele quer fazer a ordenação, clicando no titulo de uma coluna no DBgrid. Utilizaremos o IndexFieldNamesque .

7 comentários:

  1. Ana, boa tarde
    Poderia me ajudar em uma duvida?
    Tenho uma NF e preciso cadastrar esta NF e seus itens para que apareça em um DBGrid, segue um exemplo abaixo

    NF DESCRIÇÃO DO PRODUTO VALOR UNITARIO QUANTIDADE VALOR TOTAL
    1234 PARAFUSO DE AÇO R$ 0,50 10 R$ 5,00
    1234 TUBO DE SILICONE 100 ML R$ 5,00 5 R$ 25,00

    Como devo proceder neste caso? Teria algum exemplo fisico?
    Uso AdoQuery, AdoConexion, Banco de Dados Access.
    Parabens pelo Blog!!!
    No aguardo,
    Cristiano

    ResponderExcluir
    Respostas
    1. Acredito que seja um dbgrid normal consiga exibir esses dados.
      Se não é bem isso ha como passar mais detalhes de como quer? Obrigada

      Excluir
  2. Bom dia, Ana. Tenho uma dúvida, talvez você possa esclarecê-la. Tenho um DBGrid, no qual necessito " navegar entre as colunas " --- tem de ser através de um botão --- a fim de inserir dados nos diversos campos . Eu tenho de usar botões simulando as setas ( para cima, para baixo --- essas eu consigo com " prior e next " porém as setas para esquerda e direita eu não consigo codificar.Obrigado pela sua atenção.

    ResponderExcluir
    Respostas
    1. Ola Boa tarde.
      Para navegar entre colunas tem a tecla de atalho Tab para prosseguir e shift + tab para volta então seria apenas colocar em botões a simulação de cliques nessas teclas.

      Exemplo:

      Direita
      { Pressiona Tab }
      keybd_event(VK_TAB, 0, 0, 0);

      Esquerda
      { Pressiona Shift}
      keybd_event(VK_SHIFT, 0, KEYEVENTF_EXTENDEDKEY or 0, 0);
      {Preciona Tab}
      keybd_event(VK_TAB, 0, 0, 0);
      { Libera (solta) Shift }
      keybd_event(VK_SHIFT, $45, KEYEVENTF_EXTENDEDKEY or KEYEVENTF_KEYUP, 0);

      Responde ai se isso ajudou

      Excluir
  3. Boa tarde Ana, Cara gostei muito de suas dicas. Estou com um problema aki e talves vc possa me ajudar,Eu tenho um DBGrid para mostrar a lista de itens de um pedido. Quero saber se é possivel eu apenas digitar o codigo ou o nome do produto em uma das coluna do DBGrid, e as outras colunas serem preenchidas com as informações restante do produto.
    ex: ____________________________________________________________________
    | código | Descrição | Ref. | Valor_Unid | Quantidade | Valor_Total |

    Dentro do DBGrid, eu digitaria apenas o "código" do produto... e ele me retornaria com as informações das outras colunas restantes. "Descrição" "Ref." "Valor_Unid" "Quantidade" "Valor_Total".

    Isso é possivel ?
    Eu uso Delphi 7, DBxpress ( SQLDataSet, ClientDataSet...), Firebird 2.5

    ResponderExcluir
    Respostas
    1. Ola boa tarde Marcos, porque não utiliza a propriedade "OnChange" do campo "código" na tabela ClientDataSet, se no seu caso não houvesse restrição acredito que seria a melhor maneira sem precisar alterar o TDBGrid. Responde ai se isso ajudou.

      Excluir
  4. Boa tarde Ana, gostei muito do seu post, já ajudou um bocado, mas ainda enfrento um problema. tenho uma dbgrid de um contas a receber com checkbox e gostaria que ao marcar o checkbox ele somasse um valor de um determinado campo. pelo exemplo que vc deu, não estou conseguindo marcar o checkbox, já que o tratamento que vc deu já vem de um capo booleano existente na tabela. Fico agradecido pela atenção.abraços.

    ResponderExcluir