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.
Pergunta
Micheus
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:
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): 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: 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: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
Link para o comentário
Compartilhar em outros sites
0 respostass a esta questão
Posts Recomendados
Participe da discussão
Você pode postar agora e se registrar depois. Se você já tem uma conta, acesse agora para postar com sua conta.