Share Button

Hoje fiquei com vontade de escrever algo para “EU” mesmo. Um preguiçoso incondicional… Sabe aquele cara que não gosta de repetir tudo de novo… então… Já notou como RTTI fica tudo repetitivo… cansei.

Se um objeto tem um propriedade Caption, para atribuir um valor para ele usando RTTI é preciso iniciar um Context, fazer um loop para checar se a propriedade existe, ver o tipo… cansei…

Agora vou fazer assim:

label1.ContextProperties['caption'] := 'meu caption';

Alguém vai dizer que para fazer para um TLabel é moleza… tudo bem… e se fosse um objeto que não sei se tem a propriedade “caption”… tudo bem – isto não é problema meu… o objeto que se encarregue de tratar… não quero aquele erro infame na minha janela…

Vi a palestra do Thulio na Conference 2016 e ele nem piscou, mandou um “dinossauro” na sala quando falava de MongoDB – beleza meu amigo, vamos tocando aqui.

Quer saber se TMongoConnection tem uma propriedade “loginprompt” – não precisava, mas se estiver na dúvida então faz assim:

if MongoConnection.IsContextProperty('loginprompt') then
        fazUmEstragoNoDB;

Humm… pensei melhor e talvez não era uma propriedade o que esperava… na verdade era uma variável do objeto:

Opa, então faz assim:

form1.ContextFields['usuario'] := 'Eu mesmo';

Por fim, pensei em listar todas a propriedades do objeto em um memo…

Boa, isto é moleza:

label1.GetContextPropertiesItems( memo1.lines );

Se fosse uma lista de variáveis do objeto, da para fazer assim:

form1.ContextGetFieldsList( memo1.lines );

Difícil…. então deixa de falar que RTTI é complicado, bora usar aí nos seus projetos mais ousados.
Quer ver mais…. olha aqui nos fontes: https://github.com/amarildolacerda

Share Button

Um boa dor de cabeça é resolver exceções em TThread, TTasks….

Base de Conhecimento
Como pré-requisito é preciso ter em mente (“recomenda-se”) não existir uma exceção não tratada dentro de uma TThread – então todos os processo deveriam tratar as suas exceções internamente com um Try/Exception.

   Try
      código com erro...
   Except
     on e:exception do
        fazer algo...
   end;

 

No framework parte do “post” LogEvents é possível prever o tratamento de exception acrescentando o método RUN…

procedure TLogListItems.Run(proc: TProc);
begin
  TThread.CreateAnonymousThread(
    procedure
    begin
      try
        proc;
      except
        on e: exception do
          LogEvents.DoErro(nil, 0, e.message);
      end;
    end).start;
end;

Com método RUN recebendo um ANONIMOUS Procedure – permite que a aplicação faça assim:

  // usado metodo ANONIMOUS para tratar exception internamente
  LogEvents.Run(
  procedure begin
        // código com potencial de exceção

       // força um exception
       raise Exception.Create('Error Message');
  end);

Como mostrar o erro ao usuário

O Framework “LogEvents” possui um método de inicialização “register” que o formulário irá se inscrever para receber mensagens… e outro para retirar a inscrição “unregister“.

LogEvents.register(self, DoErro, 0); // recebe os registro de ERROS

onde:

  • self é o formulário que irá recebe mensagens…
  • DoErro é o método do furmulario…
  • e o terceiro parâmetro é um identificador que qualifica o tipo de mensagem que irá receber

O mesmo formulário pode subscrever a receber mais de um tipo de mensagem;


    LogEvents.register(self, DoErro, 0); // recebe os registro de ERROS
    LogEvents.register(self, DoSucesso, 1); // registra para receber os sucessos

Para não receber mensagens – em geral quando o formulário fecha “close” usar: LogEvents.unregister(self);

Enviando mensagem para o formulário

O método genérico “Log” permite enviar uma mensagem para o identificador “0” (usado no register):

LogEvents.Log(‘Minha mensagem a ser mostrada’);

Para enviar uma mensagem com um identificador específico:

LogEvents.DoErro(nil, 1, ‘LOG…..’);  // register = 1

Código de Exemplo: LogEvents – Mostrando Erros ao usuário

 

 

Share Button

Estava precisando de informações sobre uma exceção e o log de erro não dizia nada relevante possível de encontrar onde o problema ocorria.

Já vi vários posts sobre o assunto peguntando como fazer isto. Então não tive outra saída… mãos-a-obra.

(uso Delphi 10.1)

A instância  “Application” possui um evento “application.onException” que permite indicar um método para redirecionar a saída de todas as exceções não tratadas pelo aplicativo.

// preparando o evento no formulário principal
procedure TForm1.DoAppException(sender:TObject; E:Exception);
begin
   DoAppExceptionEvent(sender,e,true);
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
   Application.OnException := DoAppException;
...
end;
uses Forms, System.Classes,System.SysUtils,System.RTTI;

// grava o log em disco
procedure ErrorLog(ATexto: string);
var
  LArquivo: string;
  LTextFile: textfile;
begin
  LArquivo := 'Erros_' + formatDateTime('yyyymmdd', date) + '.log';
  ForceDirectories(ExtractFilePath(LArquivo));

  AssignFile(LTextFile, LArquivo);
  try
{$I-}
    Append(LTextFile);
{$I+}
    if IOResult <> 0 then // se o arquivo nao existe, criar um novo;
      Rewrite(LTextFile);
    WriteLn(LTextFile, ATexto);
  finally
    CloseFile(LTextFile);
  end;
end;

// monta a mensagem do log com base nos atributos do objecto que gerou a exceção
procedure DoAppExceptionEvent(Sender: TObject; E: Exception;
  AShow: boolean = True);
var
  LMsg: string;
  function GetRTTILog(ASender: TObject): string;
  var
    LNome: string;
    LContext: TRttiContext;
    LType: TRttiType;
    LProp: TRttiProperty;
    LVar: TValue;
    LTxt: String;
  begin
    result := '';
    if ASender=nil then exit;
    result := 'ClassName: ' + ASender.ClassName + #13#10;
    LContext := TRttiContext.Create;
    try
      LType := LContext.GetType(ASender.ClassType);
      for LProp in LType.GetProperties do
      begin
        try
          LVar := LProp.GetValue(ASender);
          LTxt := LVar.AsString;
          if LTxt <> '' then
            result := result + LProp.Name + ': ' + LTxt + #13#10;
        except
        end;
      end;
    finally
      LContext.Free;
    end;
  end;

begin
  try
    LMsg := '';
    if assigned(Sender) then
    begin
      LMsg := GetRTTILog(Sender);
    end;
    LMsg := LMsg + ' Message: ' + E.Message;
    ErrorLog(LMsg);
  except
    on ee: Exception do
      ErrorLog(ee.Message);
  end;
  if AShow then
  begin
    E.Message := LMsg;
    Application.ShowException(E);
  end;
end;

Share Button

Quando trabalha com FMX no delphi é praticamente obrigatório trabalhar com um arsenal de imagens para melhorar o visual. Imagens são usadas para botões, títulos, rodapés, fundo…. imagem, imagem, imagem….

Para manter um padrão de tamanho e mesmo visual de imagem o TimageList é fundamental… além de não carregar a mesma imagem em vários locais diferentes…

Para isto tudo ficar bom, precisamos retirar as imagens da lista e passar para um componente que na maioria não tem aquela propriedade experta para marcar qual o indice da imagem.

Imagine que vc queira um fundo em um TRectangle e a imagem desejada esteja em um TimageList…

var
   bmp:TCustomBitmapItem;
   n:TSize;
begin
   AImageList.BitmapItemByName(bgNome ,bmp,n);
   ABitmap.Assign( bmp.Bitmap );
end;

Nestes casos cai bem um TDatamodule para centralizar as imagens já que ele será utilizado em várias janelas do sistema.

Share Button

When I was preparing the sample code for the article on Forin to FireDAC , I remembered an article by my friend Marcos Douglas  published in Object Pascal Programming  that speaks of the Imperative or Structured programming.

In computer science, imperative programming is a programming paradigm that describes computation as actions, statements or commands that change the state (variables) of a program. Much like the imperative behavior of natural languages ​​that express orders, imperative programs are a sequence of commands to the computer running.  (Wikipedia)

The article has as objective to discuss the end of FreeAndNil proposing the use of Interface PASCAL programming. Extracting the concept is possible to write code using directly interface which demonstrates the power of language forward to the new paradigms.

Rewriting TFDQuery interface, we can do:

TQueryIntf.New (FDConnection1)
          .table ( 'sigcad a')
          .FieldNames ( 'code, name')
          .Where ( 'between code: codigo_de and: codigo_ate')
          .ParamValue ( 'codigo_de', 1)
          .ParamValue ( 'codigo_ate', 5)
          .open
          .DoQuery (Procedure (ds: TDataset)
                    begin
                         memo1.Lines.Add ( 'loaded' + IntToStr (ds.RecordCount))
                    end);

Share Button

A chave primária é responsável em manter a integridade da tabela no banco de dados e o índice de maior eficiência disponível.

Deveríamos ter uma regra obrigatória:
“NAO PODE DEIXAR DE INDICAR A CHAVE PRIMÁRIA”

Para localizar as tabelas que não possuem chave primária executar:

SELECT RDB$RELATION_NAME AS Tabela
 FROM RDB$RELATIONS
WHERE RDB$RELATION_TYPE IN (0, 4, 5)
 AND (RDB$SYSTEM_FLAG = 0 OR RDB$SYSTEM_FLAG IS NULL)
 AND RDB$RELATION_NAME NOT IN
 (SELECT RDB$RELATION_NAME FROM RDB$RELATION_CONSTRAINTS
 WHERE RDB$CONSTRAINT_TYPE = 'PRIMARY KEY')
ORDER BY RDB$RELATION_NAME;

fonte: Firebird Conference 2014 – Ivan Prenosil