Testar se uma palavra está em uma string usando AnsiContainsStr e ContainsStr


Vira e mexe precisamos testar se contém alguma palavra no meio de uma string para isso temos duas funções que podemos utilizar AnsiContainsStr e ContainsStr;

A função AnsiContainsStr é uma busca sensitive com isso ela diferencia minuscula de maiúsculas já a função ContainsStr não tem essa distinção.

procedure TFVendas_NFSe.actTesteExecute(Sender: TObject);
var
  lDescricao: String;
begin
  lDescricao := 'Meu nome é Ana Paula Novello';
  if AnsiContainsStr(lDescricao, 'novello') then begin
    ShowMessage('Nome correto');
  end else begin
    ShowMessage('Nome incorreto');
  end;
  if AnsiContainsText(lDescricao, 'novello') then begin
    ShowMessage('Nome correto');
  end else begin
    ShowMessage('Nome incorreto');
  end;
//  PreencherBoletos(True);
end;

Em negrito está marcado as opções que a função vai retornar, reparem que o novello está resultando como verdadeiro apenas na função ContainsStr isso porque na variável que está comparando esta com letra maiúscula.

Utilizando Checklistbox no Delphi 10



Buenas, hoje pela manhã vi em um fórum que muitos programadores não utilizam o checklistbox por não saberem como usar ou não ver onde ele poderia ser aplicado.

Vamos num exemplo: 

Temos um cadastro de produto, e esse produto pode ter vários grupos ou variações, então teremos de selecionar vários grupos para cada produto.

Então vamos fazer um exemplo simples, nele vamos inicializar o checklistbox com informações que teremos uma uma tabela do banco, isso será num botão.

Na função de gravar vamos colocar o comando para gravar o'que alteramos para o banco de dados.

Exemplo prático: 

Vamos ter uma tabela chamada VARIACOES que ela terá CODIGO_VAIRACAO, DESCRICAO.

Vamos ter outra tabela chamada PRODUTOS_VARIACOES, nessa tabela vamos ter CODIGO_VARIACAO e CODIGO_PRODUTO. 

Botão btnAbrirVariacoesClick vamos colocar um comando para limpar o checklistboxapós isso um SQL para trazer todas as variações e fazer vínculo com a tabela PRODUTOS_VARIACOES para ver quais já foram marcados, após isso vamos colocar um  laço de repetição para poder preencher o checklistbox.

procedure TFSistemas.btnAbrirVariacoesClick(Sender: TObject);
begin
  CheckListBox.Clear;
  FDQuery1.Close;
  FDQuery1.SQL.Text := 'select ('' '' || H.CODIGO_VARIACAO || '' - '' || H.DESCRICAO) as DESCRICAO,' +
    ' iif(AV.CODIGO_PRODUTO > 0, 1, 0) as MARCADO, H.CODIGO_VARIACAO' +
    ' from VARIACOES H' +
    ' left join PRODUTOS_VARIACOES AV on AV.CODIGO_VARIACAO = H.CODIGO_VARIACAO' +
    ' and AV.CODIGO_PRODUTO =  ' + IntToStr(tbProdutosCODIGO_PRODUTO.asInteger) +
    ' order by H.DESCRICAO';
  FDQuery1.Open;
  FDQuery1.First;
  while not FDQuery1.Eof do begin
    CheckListBox.Items.Append(FDQuery1.FieldByName('DESCRICAO').AsString);
    CheckListBox.Checked[FDQuery1.RecNo - 1] := FDQuery1.FieldByName('MARCADO').AsInteger = 1;
    FDQuery1.Next;
  end;
end;
Nossa tela esta ficando assim.


Vamos para o botão btnSalvarVariacoes agora:

procedure TFSistemas.btnSalvarVariacoesClick(Sender: TObject);
var
  lString,
  lCodigo: String;
  li: Integer;
begin
  lString := EmptyStr;
  {Verifica as variações que estão marcadas e salvar em uma variável separando por virgula}
  for li := 0 to CheckListBox.Count - 1 do begin
    if CheckListBox.Checked[li] then begin
      lCodigo := copy(CheckListBox.Items[li], 0, 50);
      lString := lString + (ifthen(lString <> '', ', ') + Trim(Copy (lCodigo, 1, Pos ('-', lCodigo) - 1)));
    end;
  end;
  {Aqui vamos deletar o conteúdo da tabela para depois fazer um insert}
  FDConnection1.ExecSQL('delete from PRODUTOS_VARIACOES' +
    ' where CODIGO_PRODUTO = ' + IntToStr(tbProdutosCODIGO_PRODUTO.asInteger));
  {Nessa parte verificamos se algum campo foi marcado se houver algum campo iremos fazer um insert na tabela}
  if Trim(lString) <> EmptyStr then begin
    FDConnection1.ExecSQL('insert into PRODUTOS_VARIACOES (CODIGO_PRODUTO, CODIGO_VARIACAO)' +
      ' select ' + IntToStr(tbProdutosCODIGO_PRODUTO.asInteger) + ', V.CODIGO_VARIACAO' +
      ' from VARIACOES V' +
      ' where V.CODIGO_VARIACAO in (' + lString + ')');
  end;
end;
Um exemplo simples da utilização, tem muitas coisas que dá para melhorar para deixar mais dinâmico para o usuário, mas vamos ver como ficou?




Criando ícone na barra de tarefas a cada Form aberto


Um código simples que hoje me salvou em um projeto.

Exemplo: Em uma ordem de serviço com a opção de abrir várias ordens ao mesmo tempo, com isso ficará vários TForm em abertos ao mesmo tempo, para poder se localizar e abrir a ordem novamente jogamos o nome do cliente para o Caption da tela e colocamos o código abaixo para poder criar um ícone na barra de tarefas do windows para cada ordem aberta. Uma dica simples mas que dependendo da necessidade e um truque muito útil.

Colocar codigo a baixo no Create do TForm.
procedure TFSistema.DoCreate;
begin
  inherited;
  SetWindowLong(Handle, GWL_ExStyle, GetWindowLong(Handle, GWL_ExStyle) or WS_EX_AppWindow);
end;
Abaixo uma mostra de como ficou com vários ícones em aberto.





 



Criar etiqueta e definindo quantidades a serem impressas no Delphi FastReport


Esse post irei fazer será um adicional de um antigo post.
Vamos supor que queremos imprimir uma folha de etiquetas mas tem algumas destas etiquetas que queremos que seja impressão mais de uma quantidade.
Para isso vamos utilizar um TClientDataSet para selecionar os produtos e as quantidades de cada etiqueta por produto, e outro TClientDataSet para receber as informações de acordo com as quantidades informadas no TClientDataSet anterior;

Vamos baixar o exemplo do post anterior e fazer nossas alterações em cima dele, no TForm vamos colocar mais um TClientDataSet com os campos que iremos imprimir na nossa etiqueta, e um TDBGrid,
e acrescentar o campo QUANTIDADE do tipo Integer no TClientDataSet já existe.


Lembramos de sempre colocar padrão para carregar 1 quantidade, senão não irá apresentar informação alguma do produto. Vamos duplicar o TClientDataSet com as informações que vamos exibir na etiqueta.

Depois disso criaremos uma Procedure com o nome de CarregarInformacoes;
procedure TFSistema.CarregarInformacoes;
var
  i: Integer;
begin
  CdsBarras.EmptyDataSet;
  CDSEtiquetas_Teste.First;
  while not CDSEtiquetas_Teste.Eof do begin
    for I := 0 to CDSEtiquetas_TesteQUANTIDADE.Value - 1 do begin
      CdsBarras.append;
      CdsBarrasDESCRICAO.Value := CDSEtiquetas_TesteDESCRICAO.Value;
      CdsBarrasCODBARRAS.Value := CDSEtiquetas_TesteCODBARRAS.Value;
      CdsBarras.Post;
    end;
    CDSEtiquetas_Teste.Next;
  end;
end;
Essa Procedure faremos um while para passar em todos os registros da tabela, e na linha de baixo um for para cadastrar a quantidade de etiquetas que informamos no TDBGrid.

O Botão de impressão da etiqueta vai ficar assim:
procedure TFSistema.btnVisualizarClick(Sender: TObject);
begin
  if CDSEtiquetas_Teste.IsEmpty then begin
    Application.MessageBox(Pchar('Seleção sem registros'), Pchar(Caption), MB_ICONINFORMATION + MB_OK + MB_DEFBUTTON1 + MB_SYSTEMMODAL);
    Exit;
  end;
  if Ler_Arquivo('Etiquetas_6x16.fr3') then begin
    CarregarInformacoes; {Nossa procedure}
    frxTable.DataSet := CdsBarras; {Joga a tabela de etiquetas que criamos nova}
    if Sender = btnVisualizar then
      frxReport.ShowReport
    else begin
      frxReport.PrepareReport;
      frxReport.Print;
    end;
  end;
end;
Percebe que coloquei no DataSet a tabela que criei depois a CdsBarras, e a procedure acima da linha onde e colocado o FrxTable.DataSet.

Vamos testar oque fizemos: 


Espero ter acendido uma pequena luz no final do túnel de como fazer um documento com três tabelas.

FastReport no Delphi - Com dois Detail


Criaremos um relatório de orçamentos, então iremos exibir os dados principais do "Cliente" e "Número do Orçamentos" e abaixo os produtos e os detalhes das parcelas. Vamos organizar esse relatório jogando os produtos para um Detail e com os totais dos produtos, e outro Detail com as parcelas.
Esse vai ser apenas um exemplo ilustrativo, sem conexão com banco de dados, vamos nos aprofundar apenas na parte do FastReport

Vamos iniciar um novo projeto (File >> New >> Windows VCL Application);

Nesse projeto vamos utilizaremos:
2 - TBitBtn;
3 - TfrxDBDataset;
1 - TfrxReport
3 - TClientDataSet;
3 - TDataSource;
1 - TEdit;

Organizei os componentes desta forma: 

Agora vamos para o FastReport.

Dê dois cliques no componente frxReport para abrir na forma de Designer, vamos iniciar (File >> New Report). Pronto criamos um novo documento ele nos trouxe como padrão ReportTitle1, MasterData1 e um PageFooter1, adicionar as tabelas no FastReport menu (Report >> Data);

Vamos comecar colocando o nosso logo no topo do relatório.

Eu coloquei manualmente o caminho utilizando um TEdit para colocar o caminho do logo, mas vocês podem colocar um campo na tabela de configuração do sistema para colocar um logo padrão da empresa com isso pode ser utilizado em outros locais do sistema.

Vamos para o FestReport

Colocamos uma linha para identificar se o logo e existe, pois se mandar um caminho invalido ocorre erro, e coloquei uma variável em branco para quando não encontrar o logo para não ocorrer o erro de não encontrar a variável no FastReport 
procedure TFSistema.BtnVisualizarClick(Sender: TObject);
begin
  if FileExists(edLogoTipo.Text) then //Identifica se existe um logo
    frxReport.Variables.Variables['LogoSistema'] := QuotedStr(edLogoTipo.Text)
  else
    frxReport.Variables.Variables['LogoSistema'] := QuotedStr('');
  frxReport.ShowReport;
end;
Com o código pronto no FastReport vamos usar a variável na parte do código
begin
  if <LogoSistema> <> '' then
    igLogo.LoadFromFile(<LogoSistema>)
end. 
Quando adicionarmos o componente que vai receber nosso logo vamos marcar algumas propriedades, Com a propriedade Stretched ativa o logo irá ocupar exatamente o tamanho que nós estipulamos, e com a propriedade HightQuality nosso logo irá ter uma qualidade melhor.

Na banda MasterData1 vamos vincular com o DataSet FrxDataSet(cdsOrcamentos), após vincular adicionar os campos "Número do Orçamento" e "Nome do cliente" o "Endereço" e outros dados que o cliente desejar. 

Organizei os componentes desta forma, vinculei a tabela frxDataset que seria a cdsOrçamentos.
Agora para os produtos vamos adicionar uma Detail e com ela vinculamos frxDataset2 com vínculo aos cdsOrcamentos_produtos abaixo do MasterData.

Agora vamos para as parcelas, vinculei a tabela frxDataset3 que seria a cdsOrçamentos_Parcelas.
Para isso iremos utilizar um Detail e com ela vinculamos frxDataset3 com vínculo aos cdsOrcamentos_parcelas abaixo do outro Detail.


Antes de irmos para os totais vamos dar uma olhada e uma "perfumada" no nosso documento, colocar o numero do orçamento no topo do documento, um espaço maior entre as parcelas e os produtos;

Agora iremos para o nosso rodapé com os totais agora, para isso vamos utilizar um ColumnFooter, para ficar no final do nosso documento, e faremos um Sum na Detail.


Resultado final 



Espero ter acendido uma pequena luz no final do túnel de como fazer um documento com três tabelas.

Erro "Incompatible types: 'System.TArray' and 'Pointer',"



O erro seguir e simples na verdade método GotoBookmark esta esperando um parâmetro um array de bytes e o SelectedRows.Items[i] retorna esse valor.


Exemplo: 
DataSet.GotoBookmark(Pointer(dbgrPrincipal.SelectedRows.Items[i]));
Então para ajustar o código acima seria apenas remover o Pointer
DataSet.GotoBookmark((dbgrPrincipal.SelectedRows.Items[i]));

Erro "Incompatible types: 'System.TArray' and 'string'"


Mas um erro na atualização do delphi 2007 para o Delphi Sydney.
A propriedade AsBlob possui um tipo TBlobData isto até o Delphi 2009, pois até então ele era declarado como string. 
Então esse erro corresponde a incompatibilidade de formado dos campos. Se você deseja atribuir uma string a um parâmetro BLOB, deve-se usar a propriedade 

Sugestão para conferir: 

1 . ParamByName('ParamName'). asBlobRef.AsString.
ou
2 . cdsPrincipalXML('NotaAssinada').AsWideString := XMLNota

Erro "Required package 'rtl' not found"


Esse erro esta relacionado a não conseguir encontrar um caminho, talvez por estar invalido (pode ocorrer quando instala um Delphi em uma maquina que já continha uma outra versão, e com isso ele se perde na hora de criar a pasta e adicionar na library path) 

Sugestão para conferir: 

  1. Se tem permissão de pasta no caminho de instalação do Delphi: C:\Program Files\Embarcadero\Studio\20.0\
  2. Adicionar as libraty path "$(BDSCOMMONDIR)\dcp" e "$(BDS)\lib";
  3. Se não "funfar" coloca na libraty path o caminho "C:\Program Files\Embarcadero\Studio\20.0\\lib\win32\release";


Já presenciou alguma outra forma de solucionar erro erro?

Método do DataSet [InsertRecord]


O método InsertRecord é uma grande facilidade para inserção de registros em um TDataSet e os que são herdado das classes TClientDataSet, TSQLDataSet, TFDQuery, FireDAC entre alguns outros componentes de conecção de banco de dados.
Quando utilizamos o InsertRecord não utilizamos o Insert/Append nem o Post. Simplesmente invocamos o método passando por parâmetro como array os valores dos campos em suas respectivas ordens.
Tem que ser atribuído exatamente a mesma quantidade de campos que contem no TDataSet e em suas respectivas ordem, quando o campo não será preenchido pode ser enviado campo null ou informação em branco ou zerada, mas tem que ser preenchido senão apresenta a mensagem "argument out of range". 

Vamos de dois exemplos uma da forma tradicional e outra com o InsertRecord.

Forma tradicional

procedure TForm1.FormCreate(Sender: TObject); begin cdsClientes.Append; cdsClientesCODIGO.Value := 1; cdsClientesDESCRICAO.Value := 'Ana Paula Novello'; cdsClientesCIDADE.Value := 'Bento Gonçalves'; cdsClientesATIVO.Value := 1; cdsClientes.Post; end;
Com o InsertRecord
procedure TForm1.FormCreate(Sender: TObject);
begin
  cdsClientes.InsertRecord([1, 'Ana Paula Novello', 'Bento Gonçalves', 1]);
  cdsClientes.InsertRecord([2, 'Davi Lavandoski',   'Garibaldi', 1]);
  cdsClientes.InsertRecord([3, 'Tassiara Novello',  'Carlos Barbosa', 1]);
end;

O contra desta forma e que tem que estar exatamente na mesma ordem que os campos esta disponíveis no DataSet mas para tabelas que tem poucos campos e uma "Mão na roda".