[Delphi] Parametrizando o comportamento de um software

[Delphi] Parametrizando o comportamento de um softwareAlô, pessoal! Na semana passada, comentei sobre a parametrização para personalizar o comportamento de um software conforme o perfil do cliente, lembram-se? Esse tipo de funcionalidade traz flexibilidade para o software, além de várias vantagens para os próprios desenvolvedores.
Mas, afinal, o que é essa parametrização, como funciona e como podemos implementá-la? “Bora” pro artigo!

 

 

Precisamos definir os parâmetros do nosso investimento, como o valor e o prazo.

Consegue identificar o sentido do emprego da palavra “parâmetros” na frase acima? Tenho certeza que sim. Significa que o valor e o prazo serão dados variáveis, e não fixos. O investimento pode ser de 40 mil para este ano e de 50 mil para o ano que vem. Em outras palavras, a definição destes parâmetros depende da situação atual. Da mesma forma, o comportamento de um software também depende de quem está o utilizando. Por exemplo, um dos usuários precisa exportar os dados de um histórico de compras no formato XLS para que possa editá-los. Outro usuário do mesmo software solicita essa exportação em formato PDF, de modo que o arquivo possa ser enviado por e-mail para vários destinatários.

 

Simples! Basta gerar um executável diferente para cada um dos usuários, não é?
No artigo sobre parâmetros na Query, levantei uma questão bem semelhante. A diferença é que, naquele artigo, expliquei a parametrização em consultas SQL e, neste artigo, explico a parametrização do comportamento do software.
Pois bem, já reparou que alguns desenvolvedores gostam de programar com fundo branco, enquanto outros preferem o fundo preto? Essa é uma opção da ferramenta de desenvolvimento, que permite a personalização conforme a preferência do desenvolvedor. Observe que não há uma versão exclusiva para cada cor de fundo. Quem define essa aparência é o usuário que utiliza a ferramenta. Então, respondendo a pergunta, não! Não devemos gerar um executável diferente para cada usuário. Temos a oportunidade de gerar um único executável e personalizar o comportamento do software para cada um deles.

 

Como?
Por meio de parâmetros, ou, talvez, você pode chamá-los de “opções”. Estes parâmetros consistem em uma tela no software que permite a definição de alguns valores para o seu funcionamento, nos quais podem ser diferentes para cada usuário do sistema. A imagem abaixo é um exemplo de uma tela de opções. Basta configurá-los para que o sistema se comporte da forma esperada.

Exemplo de parâmetros do sistema
Exemplo tela para configuração de parâmetros do sistema

 

Embora essa questão de parâmetros pareça comum, muitos desenvolvedores ainda insistem na definição de valores fixos no código-fonte. Essa prática pode oferecer uma solução pontual no software mas, cedo ou tarde, por conta do crescimento do número de usuários ou por questões arquiteturais, estes valores fixos deverão ser convertidos em parâmetros.

 

Como posso implementá-los no meu software?
Existem várias formas de codificar a gravação e a leitura de parâmetros. Neste artigo, apresentarei quatro delas. Para que o artigo não fique extenso demais, utilizarei apenas dois parâmetros nos exemplos abaixo, referente ao formato de exportação de um relatório (texto) e o número máximo de parcelas que o valor total de uma venda pode ser desdobrada (número inteiro).

 

1) Arquivos INI
Os arquivos INI são largamente utilizados para essa finalidade. Através de seções, chaves e valores, é possível gravar e ler parâmetros facilmente, já que o Delphi traz uma biblioteca exclusiva para a manipulação destes arquivos. Para gravar os valores, faça uso dos comandos a seguir:

uses
  IniFiles;
 
var
  ArquivoINI: TIniFile;
begin
  ArquivoINI := TIniFile.Create('C:\MeuAplicativo\Configuracoes.ini');
  try
    ArquivoINI.WriteString('Parametros', 'FormatoExportacao', ComboBoxFormatacao.Text);
    ArquivoINI.WriteInteger('Parametros', 'NumMaximoParcelas', StrToIntDef(EditNumParcelas.Text, 1));
  finally
    ArquivoINI.Free;
  end;
end;

 

Após a execução dos comandos acima, o arquivo será criado na seguinte estrutura:

[Parametros]
FormatoExportacao=PDF
NumMaximoParcelas=8

 

Para ler estes valores, os comandos são bem parecidos:

uses
  IniFiles;
 
var
  ArquivoINI: TIniFile;
begin
  ArquivoINI := TIniFle.Create('C:\MeuAplicativo\Configuracoes.ini');
  try
    sFormatoExportacao := ArquivoINI.ReadString('Parametros', 'FormatoExportacao', EmptyStr);
    nNumMaximoParcelas := ArquivoINI.ReadInteger('Parametros', 'NumMaximoParcelas', 1);
  finally
    ArquivoINI.Free;
  end;
end;

 

 

2) Arquivos XML
A segunda alternativa é gravar as configurações em formato XML. Para isso, é necessário utilizar o componente TClientDataSet, que traz o comando “SaveToFile” para exportar os dados. A minha sugestão é criar uma tabela temporária com os campos referentes aos parâmetros e preenchê-la em tempo de execução.
Para exportar os valores, é simples. Em primeiro lugar, é preciso verificar se os valores estão sendo adicionados ou alterados através da contagem de registros. Em seguida, preenchemos os campos, mesclamos as alterações e salvamos o arquivo:

if ClientDataSet.RecordCount = 0 then
  ClientDataSet.Append // Inclui os valores
else
  ClientDataSet.Edit; // Altera os valores
 
ClientDataSet.FieldByName('FormatoExportacao').AsString := ComboBoxFormatacao.Text;
ClientDataSet.FieldByName('NumMaximoParcelas').AsInteger := StrToIntDef(EditNumParcelas.Text, 1);
ClientDataSet.Post;
 
ClientDataSet.MergeChangeLog;
ClientDataSet.SaveToFile('C:\MeuAplicativo\Configuracoes.xml');

 

Quando for necessário ler os valores salvos, basta apenas carregar o arquivo:

ClientDataSet.LoadFromFile('C:\MeuAplicativo\Configuracoes.xml);

 

 

3) Registro do Windows
As duas alternativas acima apresentam um problema: ambas criam um arquivo físico, passível de ser alterado por um editor de texto (como o bloco de notas) ou, no pior dos casos, excluído do computador. Neste caso, como o software depende da leitura destes parâmetros, o seu funcionamento pode ficar comprometido. Como solução, pode-se gravar essas configurações no registro do Windows, que consiste em uma área do sistema operacional exclusiva para o armazenamento de configurações dos aplicativos instalados.
A gravação dos valores pode ser feita da seguinte forma:

uses
  Registry;
 
var
  Registro: TRegistry;
begin
  Registro := TRegistry.Create;
  try
    Registro.RootKey := HKEY_CURRENT_USER; // raiz
    Registro.OpenKey('Software\MeuAplicativo', True); // chave
    Registro.WriteString('FormatoExportacao', ComboBoxFormatacao.Text);
    Registro.WriteInteger('NumMaximoParcelas', StrToIntDef(EditNumParcelas.Text, 1));
    Registro.CloseKey;
  finally
    Registro.Free;
  end;
end;

 

Por sua vez, assim como acontece com os arquivos INI, a leitura é bem semelhante com a gravação:

var
  Registro: TRegistry;
begin
  Registro := TRegistry.Create;
  try
    Registro.RootKey := HKEY_CURRENT_USER; // raiz
    Registro.OpenKey('Software\MeuAplicativo', True); // chave
 
    if Registro.ValueExists('FormatoExportacao') then
      sFormatoExportacao := Registro.ReadString('FormatoExportacao');
 
    if Registro.ValueExists('NumMaximoParcelas') then
      nNumMaximoParcelas := Registro.ReadInteger('NumMaximoParcelas');
 
    Registro.CloseKey;
  finally
    Registro.Free;
  end;
end;

 

 

4) Banco de dados
Por fim, nada impede que os parâmetros do sistema sejam gravados em uma tabela no banco de dados com um nome condizente, como “PARAMETROS”, “CONFIGURACOES” ou “OPCOES”. A tabela poderá ser criada com apenas três colunas: “Codigo” (para fins de indexação), “NomeParametro” e “Valor”. Para cada parâmetro existente no sistema, um registro é adicionado nessa tabela.
Considerando que os registros já existam (por meio de uma instrução INSERT), os valores podem ser alterados através de uma Query preenchida com um comando UPDATE:

Query.SQL.Clear;
Query.SQL.Add('Update PARAMETROS set Valor = :Valor where NomeParametro = :NomeParametro');
 
Query.ParamByName('NomeParametro').AsString := 'FormatoExportacao';
Query.ParamByName('Valor').AsString := ComboBoxFormato.Text;
Query.ExecSQL;
 
Query.ParamByName('NomeParametro').AsString := 'NumMaximoParcelas';
Query.ParamByName('Valor').AsInteger := StrToIntDef(EditNumParcelas.Text, 1);
Query.ExecSQL;

 

Para ler os valores, portanto, é necessário usar o SELECT em uma instrução SQL:

Query.Close;
Query.SQL.Clear;
 
Query.SQL.Add('Select Valor from PARAMETROS where NomeParametro = :NomeParametro');
Query.ParamByName('NomeParametro').AsString := 'FormatoExportacao';
Query.Open;
sFormatoExportacao := Query.FieldByName('Valor').AsString;
 
Query.Close;
Query.ParamByName('NomeParametro').AsString := 'NumMaximoParcelas';
Query.Open;
nNumMaximoParcelas := Query.FieldByName('Valor').AsInteger;
Query.Close;

 

E qual é a melhor forma?
Fica a seu critério, caro amigo!

 

Até a próxima!
Abraço!


 

Compartilhe!
Share on FacebookTweet about this on TwitterShare on LinkedInShare on Google+Pin on PinterestEmail this to someone

4 comentários

  1. O_O Como tem coisas para eu aprender , até hoje só tinha feito arquivo ini nem imaginava que existia outros .
    Muito bom mesmo. (^_^)

  2. No caso da opção 4 (banco de dados) deve-se tomar cuidado caso a tabela seja compartilhada por outros usuários do sistema pois todos utilizarão os mesmos parâmetros . Diferente dos outros exemplos que serão validos para o computador em que sistema esteja instalado.
    Espero ter colaborado

    1. Olá, Alexandre!
      Isso mesmo. Em um sistema multiusuário, se os parâmetros estiverem armazenados no banco de dados, eles serão compartilhados para todos os usuários da aplicação, ao menos que a tabela possua uma coluna para diferenciar os parâmetros de cada usuário. Por exemplo, além dos campos que mencionei do artigo, teríamos a coluna “CodigoUsuario”, de forma que fosse possível gravar valores do mesmo parâmetro para usuários diferentes. Ao iniciar a aplicação, carregaríamos apenas as configurações do usuário conectado.

      Obrigado pela colaboração!
      Abraço!

Deixe uma resposta

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *

Preencha o campo abaixo * Time limit is exhausted. Please reload CAPTCHA.