Sign in to follow this  
Micheus

Simulando Um Dbchecklistbox

Recommended Posts

Na paleta DataControls do Delphi não existe um componente DBCheckListBox que nos permita gravar uma seleção de itens num determinado campo de uma tabela.

Ao tentar ajudar na solução desta questão neste post do colega Carlos Rocha, verifiquei que era um questionamento que já existia por aí, mas sem resposta. Resolvi então colocar nesta sessão (para que possa mais facilmente ser consultada por outros colegas), um mini-tutorial de como simular um DBCheckListBox a partir de um simples CheckListBox. (o código completo está disponível para download no final deste post)

Primeiramente, vamos observar como o "componente" deveria operar:

- Ao ser posicionado um registro, o CheckListBox deve mostrar marcado os itens que estão gravados no campo apropriado;

- Ao marcarmos ou desmarcarmos um item, isto deveria se refletir no campo sendo editado, onde o nº da posição marcada seria armazenado; Sem esquecer de que, se não estiver em modo edição, devemos verificar se o DataSource está configurado para AutoEdit e então pôr o dataset em modo edição.

Estarei utilizando a gravação do índice que aponta para o item marcado, mas poderíamos gravar o texto do item selecionado. O procedimento seria semelhante. A vantagem sobre utilizar um ou outro fica a critério de cada um.

O componente CheckListBox armazena a informação sobre qual item está marcado na propriedade Checked. Esta propriedade é um array com o nº de posições igual ao nº de itens configurados na lista.

Vamos, então, precisar criar um procedimento que possa ler os itens marcados e montar uma string com este valor para que a mesma possa ser gravada no banco:

...
implementation
{$R *.dfm}

const
  Delimitador = ',';

// Este procedimento é responsável por ler o valor gravado
// no campo da tabela e mostrá-lo no CheckListBox
procedure TForm1.PopulaCheckListBox;
var
  Idx :Integer;
  OpcStr :string;
begin
 // limpa seleção
  for Idx := 0 to CheckListBox1.Count -1 do
    CheckListBox1.Checked[Idx] := False;

  OpcStr := Table1Opcao_PrazoNum.AsString;
  while OpcStr <> '' do
  begin
    Idx := Pos(Delimitador, OpcStr);
   // não encontrar o delimitador, significa que o
   // resto da string contém o último valor
    if Idx = 0 then
     // neste caso, marcamos posição como posterior ao último caracter
      Idx := Length(OpcStr) +1;
   // Marca como selecionado o item lido
    CheckListBox1.Checked[StrToInt(Copy(OpcStr, 1, Idx -1))] := True;
   // elimina o item já processado da lista - em OpsStr
    Delete(OpcStr, 1, Idx);
  end;
end;
Para que ao movimentarmos a posição do registro na tabela, mais facilmente observado quando utilizamos DBGrid para mostrar os dados na mesma tela em que cadastramos, nós utilizaremos o evento OnDataChange do componente TDataSource que está ligado aos componentes de edição (no nosso caso, também será o mesmo que o do DBGrid). Este evento ocorre a cada modificação de um campo do dataset, então deve ser utilizado com moderação. Nós só atualizaremos a lista, a partir do registro atualmente selecionado, somente quando o dataset estiver no modo visualização (dsBrowse):
procedure TForm1.DataSource1DataChange(Sender: TObject; Field: TField);
begin
 // vamos manipular a lista apenas no modo exibição
  if (Sender as TDataSource).State = dsBrowse then
    PopulaCheckListBox;
end;
Nosso próximo objetivo é que ao marcarmos/desmarcarmos um item, o campo seja atualizado. Utilizaremos o evento OnClickCheck do componente CheckListBox. Este evento ocorre justamente nestas situações:
procedure TForm1.CheckListBox1ClickCheck(Sender: TObject);
var
  Idx :Integer;
begin
 // verificamos se é possível colocar a tabela em modo 
 // edição apenas click direto sobre a lista
  if DataSource1.AutoEdit then
    DataSource1.Edit
  else
    Exit;
 // o campo pode ser limpo em qualquer situação, pois, se for o caso,
 // será novamente prenchido com os valores atuais. Se cancel for
 // utilizando, as informações não serão perdidas

  Table1Opcao_PrazoNum.Clear;
 // *** ilustrando como seria se gravássemos o texto ao invés do índice
 // Table1Opcao_PrazoStr.Clear;
 // verifica para cada elemento da lista, se algum está marcado
  for Idx := 0 to CheckListBox1.Count -1 do
  begin
   // apenas se estiver marcado contatena no campo
    if CheckListBox1.Checked[Idx] then
    begin
      Table1Opcao_PrazoNum.AsString := Table1Opcao_PrazoNum.AsString + IntToStr(Idx) +Delimitador;
     // *** ilustrando como seria se gravássemos o texto ao invés do índice
     // Table1Opcao_PrazoStr.AsString := Table1Opcao_PrazoStr.AsString + CheckListBox1.Items[Idx] +Delimitador;
    end;
  end;
 // retira o delimitador que fica sobrando no final
  Table1Opcao_PrazoNum.AsString := Copy(Table1Opcao_PrazoNum.AsString, 1, Length(Table1Opcao_PrazoNum.AsString) -1);
 // *** ilustrando como seria se gravássemos o texto ao invés do índice
 // Table1Opcao_PrazoStr.AsString := Copy(Table1Opcao_PrazoStr.AsString, 1, Length(Table1Opcao_PrazoStr.AsString) -1);
end;
No caso de optar por gravar o texto e não o índice, basta que nas linhas do código acima sejam suprimidas as que contém Opcao_PrazoNum e sejam retirados os comentários das que contém Opcao_PrazoStr. Já a procedure PopulaCheckListBox deve ser substituída pelo código abaixo:
procedure TForm1.PopulaCheckListBox;
var
  Idx :Integer;
  OpcStr :string;
begin
 // limpa seleção
  for Idx := 0 to CheckListBox1.Count -1 do
    CheckListBox1.Checked[Idx] := False;

  OpcStr := Table1Opcao_PrazoStr.AsString;
  while OpcStr <> '' do
  begin
    Idx := Pos(Delimitador, OpcStr);
   // não encontrar o delimitador, significa que o
   // resto da string contém o último valor
    if Idx = 0 then
     // neste caso, marcamos posição como posterior ao último caracter
      Idx := Length(OpcStr) +1;
   // Marca como selecionado o item lido
    if CheckListBox1.Items.IndexOf(Copy(OpcStr, 1, Idx -1)) >= 0 then
      CheckListBox1.Checked[CheckListBox1.Items.IndexOf(Copy(OpcStr, 1, Idx -1))] := True;
   // elimina o item já processado da lista - em OpsStr
    Delete(OpcStr, 1, Idx);
  end;
end;

Espero que consigam ajustar às suas necessidades. O exemplo está em anexo, se houver problemas também pode ser baixado deste link.

Abraços

DBCheckListBox.zip

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
Reply to this topic...

×   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