• 0
Sign in to follow this  
Halan Lopes

(Resolvido) Colocar um checkbox em um DBGrid

Question

14 answers to this question

Recommended Posts

  • 0

coloquei o codigo desse site mas deu o seguinte erro!

Projeto.exe raised exception class EstackOverflow with message 'Stack overflow'. Process stopped.

que erro é esse? e como resolve-lo?

Share this post


Link to post
Share on other sites
  • 0

olha como coloquei o codigo!

procedure TfrmPagamento.FormCreate(Sender: TObject);
begin
DBCheckBox1.ValueChecked:='Pago';
DBCheckBox1.ValueUnchecked:='';
end;

procedure TfrmPagamento.DBGrid1DrawColumnCell(Sender: TObject;
  const Rect: TRect; DataCol: Integer; Column: TColumn;
  State: TGridDrawState);
const IsChecked: array[Boolean] of Integer=
      (DFCS_BUTTONCHECK, DFCS_BUTTONCHECK or DFCS_CHECKED);
var
   DrawState: Integer;
   DrawRect: TRect;
begin
  if (gdFocused in State) then
  begin
    if (Column.Field.FieldName = DBCheckBox1.DataField) then
    begin
      DBCheckBox1.Left:= Rect.Left+DBGrid1.Left+2;
      DBCheckBox1.Top:= Rect.Top+DBGrid1.Top+2;
      DBCheckBox1.Width:=Rect.Right-Rect.Left;
      DBCheckBox1.Height:=Rect.Bottom-Rect.Top;
      DBCheckBox1.Visible:=True;
    end
  end
  else
  begin
    if(Column.Field.FieldName = DBCheckBox1.DataField) then
    begin
      DrawRect:=Rect;
      InflateRect(DrawRect,-1,-1);

      DrawState:= IsChecked[Column.Field.AsBoolean];

      DBGrid1.Canvas.FillRect(Rect);
      DrawFrameControl(DBGrid1.Canvas.Handle, DrawRect, DFC_BUTTON, DrawState);
    end;
  end;
end;


procedure TfrmPagamento.DBGrid1ColExit(Sender: TObject);
begin
  if DBGrid1.SelectedField.FieldName = DBCheckBox1.DataField then
     DBCheckBox1.Visible:=False
end;

procedure TfrmPagamento.DBGrid1KeyPress(Sender: TObject; var Key: Char);
begin
  if (Key= chr(9)) then Exit;

  if (DBGrid1.SelectedField.FieldName = DBCheckBox1.DataField) then
  begin
    DBCheckBox1.SetFocus;
    SendMessage(DBCheckBox1.Handle, WM_CHAR, word(Key), 0);
  end;
end;

procedure TfrmPagamento.DBCheckBox1Click(Sender: TObject);
begin
  if DBCheckBox1.Checked then
     DBCheckBox1.Caption:=DBCheckBox1.ValueChecked
  else
     DBCheckBox1.Caption:=DBCheckBox1.ValueUnchecked;
end;

end.

Share this post


Link to post
Share on other sites
  • 0

Eu testei aqui e funcionou... o seu campo é booleano?

Coloque tmb no Create

 DBCheckBox1.DataSource := DataSource1;
 DBCheckBox1.DataField  := 'Campo';
 DBCheckBox1.Visible    := False;
 DBCheckBox1.Color      := DBGrid1.Color;
 DBCheckBox1.Caption    := '';

Abs.

Kiko

Share this post


Link to post
Share on other sites
  • 0

Vou ressusitar esse tópico pois não encontro minha resposta por ai, e quando o cara aqui no forum respondeu, passou por email e não ficamos sabendo a solução.

Eu adicionei um DBCheckbox ao projeto e desenhei ele no onDrawCollumnCell de acordo com uma pesquisa de SQL.

só que pelo que percebi nos exemplos eu só consigo selecionar um campo e quando saio e seleciono outro ele des-seleciona o antigo.

O que preciso é tipo um DBCheckBoxClick que selecione os que eu cliquei e deixe marcado. Tentei nesse evento mas não tive sucesso.

O código assim está

procedure Tfrm_pesq_nfp.grd_notasDrawColumnCell(Sender: TObject;
  const Rect: TRect; DataCol: Integer; Column: TColumn;
  State: TGridDrawState);
const IsChecked : array[Boolean] of Integer =
      (DFCS_BUTTONCHECK, DFCS_BUTTONCHECK or DFCS_CHECKED);
var
  DrawState: Integer;
  DrawRect: TRect;

begin

  if grd_notas.DataSource.DataSet.FieldByName('NF_CANCELADA').AsString = 'S' then
  begin
    if (Column.Field.FieldName = DBCheckBox1.DataField) then
    begin
     DBCheckBox1.Left := Rect.Left + grd_notas.Left + 2;
     DBCheckBox1.Top := Rect.Top + grd_notas.top + 2;
     DBCheckBox1.Width := Rect.Right - Rect.Left;
     DBCheckBox1.Height := Rect.Bottom - Rect.Top;
     DBCheckBox1.Visible := True;
    end;
  end
  else
  begin
    if (Column.Field.FieldName = DBCheckBox1.DataField) then
    begin
      DrawRect:=Rect;
      InflateRect(DrawRect,-1,-1);
      DrawState := ISChecked[Column.Field.AsBoolean];
      grd_notas.Canvas.FillRect(Rect);
      DrawFrameControl(grd_notas.Canvas.Handle, DrawRect,
        DFC_BUTTON, DrawState);
    end;
  end;

end;

Estou pedindo já porque terei que criar outro Field ao lado desse NF_CANCELADA o qual o cliente poderá optar por selecionar os checks ou não e ele pode selecionar varios.

Componentes utilizados IBQuery, DBCheckBox, DBGrid, DataSource.

abraço

Share this post


Link to post
Share on other sites
  • 0

O que preciso é tipo um DBCheckBoxClick que selecione os que eu cliquei e deixe marcado. Tentei nesse evento mas não tive sucesso.
Exemplo
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  Provider, DBClient, Db, DBTables, Grids, DBGrids;

type
  TForm1 = class(TForm)
    DBGrid1: TDBGrid;
    DataSource1: TDataSource;
    Query1: TQuery;
    ClientDataSet1: TClientDataSet;
    DataSetProvider1: TDataSetProvider;
    procedure SaveBoolean;
    procedure DBGrid1CellClick(Column: TColumn);
    procedure DBGrid1DrawColumnCell(Sender: TObject; const Rect: TRect;
      DataCol: Integer; Column: TColumn; State: TGridDrawState);
    procedure DBGrid1ColEnter(Sender: TObject);
    procedure DBGrid1ColExit(Sender: TObject);
  private
    { Private declarations }

     // Must declare a a global variable for this form

     FOriginalOptions : TDBGridOptions;
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.DFM}

procedure TForm1.SaveBoolean;
begin
   Self.DBGrid1.SelectedField.Dataset.Edit;
   Self.DBGrid1.SelectedField.AsBoolean := not Self.DBGrid1.SelectedField.AsBoolean;
   Self.DBGrid1.SelectedField.Dataset.Post;
end;

procedure TForm1.DBGrid1CellClick(Column: TColumn);
begin
   if Self.DBGrid1.SelectedField.DataType = ftBoolean then
      SaveBoolean();
end;

procedure TForm1.DBGrid1DrawColumnCell(Sender: TObject; const Rect: TRect;
  DataCol: Integer; Column: TColumn; State: TGridDrawState);
Const
 CtrlState : array[Boolean] of Integer = (DFCS_BUTTONCHECK,
      DFCS_BUTTONCHECK or DFCS_CHECKED);
var
   CheckBoxRectangle : TRect;
begin
   if Column.Field.DataType = ftBoolean then
      begin
         Self.DBGrid1.Canvas.FillRect(Rect);
         CheckBoxRectangle.Left := Rect.Left + 2;
         CheckBoxRectangle.Right := Rect.Right - 2;
         CheckBoxRectangle.Top := Rect.Top + 2;
         CheckBoxRectangle.Bottom := Rect.Bottom - 2;
         DrawFrameControl(Self.DBGrid1.Canvas.Handle,
         CheckBoxRectangle, DFC_BUTTON,
         CtrlState[Column.Field.AsBoolean]);
      end;
end;

procedure TForm1.DBGrid1ColEnter(Sender: TObject);
begin
   if Self.DBGrid1.SelectedField.DataType = ftBoolean then
      begin
         Self.FOriginalOptions := Self.DBGrid1.Options;
         Self.DBGrid1.Options := Self.DBGrid1.Options - [dgEditing];
      end;
end;

procedure TForm1.DBGrid1ColExit(Sender: TObject);
begin
   if Self.DBGrid1.SelectedField.DataType = ftBoolean then
      Self.DBGrid1.Options := Self.FOriginalOptions;
end;

end.

obs: Voce deve definir os campos como Boolean ou Logical

abraço

Share this post


Link to post
Share on other sites
  • 0

Eu acho que entendi como que funciona, mas não consegui testar justamente por causa de passar o Column.Field.DataType para ftBoolean. Quando vejo seu valor aqui é sempre ftInter. Procurei tanto na grid quanto no field do dataset mas não achei essa propriedade. Acho que o primeiro passo seria converter int para boolean mas não descobri como fazer isso ...

Share this post


Link to post
Share on other sites
  • 0
Eu acho que entendi como que funciona, mas não consegui testar justamente por causa de passar o Column.Field.DataType para ftBoolean. Quando vejo seu valor aqui é sempre ftInter. Procurei tanto na grid quanto no field do dataset mas não achei essa propriedade. Acho que o primeiro passo seria converter int para boolean mas não descobri como fazer isso ...

Os campos Boolean foram inseridos no Interbase apartir da versão 7.1,

porém para as versões anteriores do Interbase podemos criar

Domains para resolver este problema

Exemplos:

1:

CREATE DOMAIN TIPO_BOOLEAN AS CHAR(1) DEFAULT 'N' NOT NULL CHECK (VALUE IN ('S','N'));

Onde 'S' representa true e 'N' false.

2:

CREATE DOMAIN BOOLEAN AS

CHAR(1) CHARACTER SET WIN1252

COLLATE WIN1252

3:

CREATE DOMAIN T_BOOLEAN_INT CREATE DOMAIN T_BOOLEAN_INT

AS SMALLINT AS SMALLINT

DEFAULT 0 DEFAULT 0

NOT NULL NOT NULL

CHECK (VALUE IN (0,1)) CHECK (VALUE IN (0,1))

Esse domínio deve ser necessariamente um tipo smallint ou tipo inteiro, que permite que dois valores possíveis "0" e "1" e contém a palavra "boolean" em seu nome.

4:

CREATE DOMAIN T_BOOLEAN_CHAR CREATE DOMAIN T_BOOLEAN_CHAR

AS CHAR(1) AS CHAR (1)

DEFAULT 'F' F 'default'

NOT NULL NOT NULL

CHECK (VALUE IN ('T', 'F')) CHECK (VALUE IN ( 'T', 'F'))

Campos criados com estes domínios são considerados booleanos e com a ajuda de componentes visuais são mostrados para os usuários. Em especial se estiver usando TDBCheckBox você pode mostrar as propriedades, tais como ValueChecked: = 'T' e ValueUnchecked: = 'F'. Neste caso, o componente irá se comportar como um campo boolean real.

A unica mudança no código seria esta

procedure TForm1.DBGrid1DrawColumnCell(Sender: TObject; const Rect: TRect;
  DataCol: Integer; Column: TColumn; State: TGridDrawState);
Const
CtrlState : array[Boolean] of Integer = (DFCS_BUTTONCHECK,
      DFCS_BUTTONCHECK or DFCS_CHECKED);
var
   CheckBoxRectangle : TRect;
begin
   if (Column.Field.FieldName = 'TESTE') then   //  mudança no código
      begin
         Self.DBGrid1.Canvas.FillRect(Rect);
         CheckBoxRectangle.Left := Rect.Left + 2;
         CheckBoxRectangle.Right := Rect.Right - 2;
         CheckBoxRectangle.Top := Rect.Top + 2;
         CheckBoxRectangle.Bottom := Rect.Bottom - 2;
         DrawFrameControl(Self.DBGrid1.Canvas.Handle,
         CheckBoxRectangle, DFC_BUTTON,
         CtrlState[Column.Field.AsBoolean]);
      end;
end;

OBS: O campo TESTE foi criado como Char de 1 posição e neste caso só aceita 'F' false ou 'T' true

O Paradox aceita campos do tipo Logical 'L'

abraço

Share this post


Link to post
Share on other sites
  • 0

Bom, fiz como voce falou, mas continuo com problema. Até consegui mostrar os campos T como checked e F como unchecked só que não estou conseguindo dar o SaveBoolean pra armazenar a minha opção de selecionado.

procedure Tfrm_faturamento.grdFaturamentoCellClick(Column: TColumn);
begin

if grdFaturamento.SelectedField.DataType = ftBoolean then
      SaveBoolean();
end;
Agora o DataType aí está marcando ftString.
CREATE TABLE
...
FATURADO            DM_BOOLEAN /* DM_BOOLEAN = CHAR(1) */

CREATE DOMAIN DM_BOOLEAN AS
CHAR(1) CHARACTER SET NONE
COLLATE NONE
Esse foi o domínio que criei pro campo FATURADO e não consigo pegar ele na grid. Fiz um teste básico para ver se funcionava.
SELECT VEN_COD_PEDIDO, VEN_TOTAL, VEN_DATA, FATURADO FROM VENDAS
ORDER BY VEN_COD_PEDIDO

No botão pesquisar eu dou um Open nessa query e me mostra os resultados. o CheckBox está ligado ao mesmo DataSource da grid que está ligado a query. O DataField do Check tá marcado com o campo FATURADO. As propriedades ValueChecked tá como True e Unchecked como False.

Detalhe: mesmo eu forçando entrar no SaveBoolean colocando ftString, quando executa a procedure dá erro de Read-Only dataset. Acredito que é porque estou manipulando um dataset que está sendo ali visualizado apenas como leitura. Teria que ter outro com instruções UPDATE?

motivo edit: Acrescentar o Detalhe

Edited by DiabloX3

Share this post


Link to post
Share on other sites
  • 0
continuo com problema. Até consegui mostrar os campos T como checked e F como unchecked só que não estou conseguindo dar o SaveBoolean pra armazenar a minha opção de selecionado.

Fiz um teste aqui, usando um campo chamado OPC como varchar de 1 posição ... está funcionando legal

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  Grids, DBGrids, Db, DBTables, Provider, DBClient;

type
  TForm1 = class(TForm)
    Query1: TQuery;
    DataSource1: TDataSource;
    DBGrid1: TDBGrid;
    ClientDataSet1: TClientDataSet;
    DataSetProvider1: TDataSetProvider;
    ClientDataSet1PAPEL: TStringField;
    ClientDataSet1COD: TStringField;
    ClientDataSet1NUM: TFloatField;
    ClientDataSet1OPC: TStringField;
    procedure SaveBoolean;
    procedure DBGrid1CellClick(Column: TColumn);
    procedure DBGrid1DrawColumnCell(Sender: TObject; const Rect: TRect;
      DataCol: Integer; Column: TColumn; State: TGridDrawState);
    procedure DBGrid1ColEnter(Sender: TObject);
    procedure DBGrid1ColExit(Sender: TObject);
  private
    { Private declarations }

     // Must declare a a global variable for this form

     FOriginalOptions : TDBGridOptions;
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.DFM}

procedure TForm1.SaveBoolean;
begin
   Self.DBGrid1.SelectedField.Dataset.Edit;
   Self.DBGrid1.SelectedField.AsBoolean := not Self.DBGrid1.SelectedField.AsBoolean;
   Self.DBGrid1.SelectedField.Dataset.Post;
end;

procedure TForm1.DBGrid1CellClick(Column: TColumn);
begin
   if Self.DBGrid1.SelectedField.DataType = ftBoolean then
      SaveBoolean();
end;

procedure TForm1.DBGrid1DrawColumnCell(Sender: TObject; const Rect: TRect;
  DataCol: Integer; Column: TColumn; State: TGridDrawState);
Const
CtrlState : array[Boolean] of Integer = (DFCS_BUTTONCHECK,
      DFCS_BUTTONCHECK or DFCS_CHECKED);
var
   CheckBoxRectangle : TRect;
begin
   if (Column.Field.FieldName = 'OPC') then   //  mudança no código
      begin
         Self.DBGrid1.Canvas.FillRect(Rect);
         CheckBoxRectangle.Left := Rect.Left + 2;
         CheckBoxRectangle.Right := Rect.Right - 2;
         CheckBoxRectangle.Top := Rect.Top + 2;
         CheckBoxRectangle.Bottom := Rect.Bottom - 2;
         DrawFrameControl(Self.DBGrid1.Canvas.Handle,
         CheckBoxRectangle, DFC_BUTTON,
         CtrlState[Column.Field.AsBoolean]);
      end;
end;

procedure TForm1.DBGrid1ColEnter(Sender: TObject);
begin
   if Self.DBGrid1.SelectedField.DataType = ftBoolean then
      begin
         Self.FOriginalOptions := Self.DBGrid1.Options;
         Self.DBGrid1.Options := Self.DBGrid1.Options - [dgEditing];
      end;
end;

procedure TForm1.DBGrid1ColExit(Sender: TObject);
begin
   if Self.DBGrid1.SelectedField.DataType = ftBoolean then
      Self.DBGrid1.Options := Self.FOriginalOptions;
end;

end.

abraço

Share this post


Link to post
Share on other sites
  • 0

Descobri meu erro Jhonas.

Eu não uso no meu sistema os componentes clientdataset nem datasetprovider.

Dai coloquei eles e deu certo. Grato Jhonas.

a propósito, isso seria uma simples opção ou um erro? desconheço a boa (ou não) utilidade desses 2 componentes.

Share this post


Link to post
Share on other sites
  • 0
a propósito, isso seria uma simples opção ou um erro? desconheço a boa (ou não) utilidade desses 2 componentes.
Digamos que quando voce usa esses 2 componentes, voce não corre o risco de perder seus dados numa eventual queda de energia elétrica.

Descriçao do TClientDataSet e do TDataSetProvider pelo help do delphi

TClientDataSet implements a database-independent dataset.

Unit

dbclient

Description

TClientDataSet encapsulates a database-independent, distributed dataset. A client dataset can be used as a

Fully-functional, standalone, flat-file dataset for single-tiered database applications. When used in this manner, an application uses the client dataset to read from and write to a user’s hard disk directly, without accessing a database engine.

Client dataset in the client application portion of a multi-tiered database application.

Note: The two functions described above are not mutually exclusive. A multi-tiered application can be designed to support the option of working with data off-line, using the “briefcase” model. On site, the application uses TClientDataSet to communicate with the application server’s data provider. When a user works off site, the client dataset writes a snapshot of the data to the hard disk. The application works with this snapshot off site, with the client dataset acting as a flat-file dataset in a single-tiered application.

The client dataset can communicate with a data provider directly by calling the provider component’s methods. When used in a client application as part of a multi-tiered application, the client dataset passes all calls to the provider through the remote data module’s IAppServer interface.

Note: See the Midas demos for examples of how to use TClientDataSet.

TDataSetProvider provides data from and resolves data to a dataset or database.

Unit

provider

Description

Use TDataSetProvider to provide data from a dataset to a client dataset and to resolve updates from a client dataset back to that dataset or to its underlying database. TDataSetProvider is usually placed in the application server of a multi-tiered application. It serves as a data broker between a remote database server and a client dataset in the desktop client application.

TDataSetProvider packages data from a dataset and passes it in one or more transportable data packets to the client dataset. The client dataset receives the data packets and reconstructs the data to create a local, in-memory copy for user access. When user access is complete, the client dataset repackages any changed data and sends the updates to the provider on the application server. The provider applies the updates back to the dataset or its underlying database table.

Client applications can access TDataSetProvider methods using the IAppServer interface of the remote data module that contains the provider.

Maiores informações consulte apostilas:

http://imasters.uol.com.br/artigo/3947/des...e_suas_funcoes/

http://www.t2ti.com/curso/video/delphi/ini...phi_starter.php

abraço

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Answer this question...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Sign in to follow this