quinta-feira, 17 de agosto de 2017

Deletar um diretório inteiro de uma vez

Problemas para deletar um diretório com subdiretórios? Utilize a função abaixo:

Uses
  Shellapi, filectrl, //declare estas das units!!!

function DeleteFolder(FolderName: String; LeaveFolder: Boolean): Boolean;
var
  r: TshFileOpStruct;
begin
  Result := False;
  if not DirectoryExists(FolderName) then
  Exit;
  if LeaveFolder then
  FolderName := FolderName + ' *.* '
  else
  if FolderName[Length(FolderName)] = ' \ ' then
  Delete(FolderName,Length(FolderName), 1);
  FillChar(r, SizeOf(r), 0);
  r.wFunc := FO_DELETE;
  r.pFrom := PChar(FolderName);
  r.fFlags := FOF_ALLOWUNDO or FOF_NOCONFIRMATION;
  Result := ((ShFileOperation(r) = 0) and (not r.fAnyOperationsAborted));
end;
Usa-se Assim:

procedure TForm1.Button1Click(Sender: TObject);
begin
  deleteFolder('c:\temp',false);
end;
  

Criar sub-diretório no diretório do EXE

Inclua na seção uses: FileCtrl, SysUtils

Problema:

Gostaria de criar um sub-diretório dentro do diretório onde se encontra o EXE de minha aplicação. Como fazer?

Solução: 

Primeiramente vamos conhecer algumas funções do Delphi que precisaremos usá-las:

ParamStr(Indice) - Retorna valores passados na linha de comando quando executamos o programa. Se o valor de Indice for 0 (zero) será retornado o caminho+nome do EXE. 

ExtractFilePath(NomeArq) - Retorna o caminho (path) do nome de arquivo informado. 

Exemplo: 

S := 'C:\NomeDir\Programa.exe';
ExtractFilePath(S); { retorna: 'C:\NomeDir\' }
DirectoryExists(CaminhoDir) - Retorna true se o diretório informado existe. False em caso contrário.

CreateDir(CaminhoDir) - Tenta criar o diretório informado.

Se conseguir, retorna true. Caso contrário retorna false.

Agora que sabemos como trabalham estas funções, vamos escrever uma função que precisamos para criar um sub-diretório conforme proposto.

function CriaSubDir(const NomeSubDir: string): boolean;
var
  Caminho: string;
begin
  Caminho := ExtractFilePath(ParamStr(0)) + NomeSubDir;
  if DirectoryExists(Caminho) then
  Result := true
  else
  Result := CreateDir(Caminho);
end;
Exemplo de uso:

- Chame a função no evento OnCreate do form:

procedure TForm1.FormCreate(Sender: TObject);
begin
  if not CriaSubDir('MeuSubDir') then
  ShowMessage('Não foi possível criar o sub-diretório MeuSubDir.');
end;

quarta-feira, 16 de agosto de 2017

Criando diretório

Para criar um diretório você precisa usar a função ForceDirectories, o exemplo a baixo testa se não existe um diretório e cria o diretório apartir de uma variável string testando se o diretório já existe 

Unit

FileCtrl

procedure TForm1.Button1Click(Sender: TObject);
var
  Dir: string;
begin
Dir := 'C:\APPS\SALES\LOCAL';

if not DirectoryExists(Dir) then
  ForceDirectories(Dir);
  Label1.Caption := Dir + ' foi criado';
end;

Copiar arquivos usando curingas (*.*)

Coloque um Button no Form;
Altere o evento OnClick deste Button conforme abaixo: 

procedure TForm1.Button2Click(Sender: TObject);
var
  SR: TSearchRec;
  I: integer;
  Origem, Destino: string;
begin
  I := FindFirst('c:\Origem\*.*', faAnyFile, SR);
  while I = 0 do begin
  if (SR.Attr and faDirectory) <> faDirectory then begin
  Origem := 'c:\Origem\' + SR.Name;
  Destino := 'c:\Destino\' + SR.Name;
  if not CopyFile(PChar(Origem), PChar(Destino), true) then
  ShowMessage('Erro ao copiar ' + Origem + ' para ' + Destino);
  end;
  I := FindNext(SR);
  end;
end;
Observações

No exemplo acima, se o arquivo já existir no destino, a função falha (não copia). Para que a função possa sobreescrever o arquivo destino (caso exista), altere o último parâmetro de CopyFile para false. CUIDADO! Se um arquivo for sobreescrito, estará perdido para sempre! 

Copiando Um Arquivo Com Um Gauge

Muitas vezes, quando temos a necessidade de copiar um arquivo de um lugar para outro, é interessante mostrar ao usuário o andamento da cópia.
Para tal, coloque em sua aplicação um gauge (optei por um gauge, mas poderia muito bem ser uma progressbar) e um botão para iniciar a cópia. No código onClick do botão, coloque este código. Neste exemplo, o programa cria um diretório de back-up cujo nome do mesmo é a data da cópia no formato AAAAMMDD. No nosso exemplo, chamei o gauge de ga_copia.

procedure Tfrm_Manut.bt_backupClick(Sender: TObject);
var
  strArqOrigem, // Nome do arquivo de origem da cópia
  strArqDestino: string; // Nome do arquivo de destino da cópia
  wDia,wMes,wAno: Word;
begin
  try
    // Aciona o indicativo de progresso da cópia
    ga_copia.Visible := True;
    ga_copia.Progress := 0;
    // Monta os nomes de arquivo - Primeiro recupera de um AdoConnection
    // o nome do arquivo a ser copiado
    strArqOrigem := dm_spark.ADO_Spark.Properties[7].Value;
    // Agora vai montar o nome do arquivo de destino.
    DecodeDate(Date, wAno, wMes, wDia);
    strArqDestino := 'C:\prodata\copia\' + FormatFloat('0000', WAno);
    strArqDestino := strArqDestino + FormatFloat('00', wMes);
    strArqDestino := strArqDestino + FormatFloat('00', wDia);
    strArqDestino := strArqDestino + '\' + ExtractFileName(strArqOrigem);
    // Desconecta o banco de dados
    dm_spark.ADO_Spark.Close;
    Repaint;
    // Inicia a cópia
    CopyFile(strArqOrigem, strArqDestino);
  finally
    // Reconecta o banco de dados
    dm_spark.ADO_Spark.Open;
    ga_copia.Visible := False;
  end;
end;



Agora que já definimos como e quando a cópia será disparada, vamos definir a procedure copyfile que é o motor da nossa cópia de arquivo. Esta procedure é que vai fazer a cópia e incrementar o Gauge.

procedure Tfrm_Manut.CopyFile(Source, Destination: string);
var
  FromF,ToF: file of byte;
  Buffer: array[0..4096] of char;
  NumRead: Integer;
  FileLength: LongInt;
  NewPath: string;
begin
  // Antes de copiar, verifica se já existe o diretório
  // Caso o diretório não exista, o mesmo vai ser criado
  NewPath := ExtractFilePath(Destination);
  if not DirectoryExists(NewPath) then
  begin
    CreateDir(NewPath);
  end
  else
  begin
    if FileExists(Destination) then
    begin
      if Application.MessageBox('O arquivo-destino da cópia de segurança já existe ' + #13#10 +
        'Deseja sobrepôr o mesmo com a nova cópia ?', 'Segurança',
        MB_YESNO + MB_ICONQUESTION) = MRNO then
        Exit;
    end;
  end;
  // Copia o arquivo
  // Abre o arquivo de origem e cria o arquivo destino
  AssignFile(FromF, Source);
  Reset(FromF);
  AssignFile(ToF, Destination);
  ReWrite(ToF);
  FileLength := FileSize(FromF);
  with ga_copia do
  begin
    MinValue := 0;
    MaxValue := FileLength;
    while FileLength > 0 do
    begin
      BlockRead(FromF, Buffer[0], SizeOf(Buffer), NumRead);
      FileLength := FileLength - NumRead;
      BlockWrite(ToF, Buffer[0], NumRead);
      AddProgress(NumRead);
    end;
    CloseFile(FromF);
    CloseFile(ToF);
  end;
end;

Abrir arquivos com aplicativo associado

Inclua a unit SHELLAPI na clausula uses do seu form.

procedure TForm1.ExecFile(F: String);
var
r: String;
begin
case ShellExecute(Handle, nil, PChar(F), nil, nil, SW_SHOWNORMAL) of
ERROR_FILE_NOT_FOUND: r := 'The specified file was not found.';
ERROR_PATH_NOT_FOUND: r := 'The specified path was not found.';
ERROR_BAD_FORMAT: r := 'The .EXE file is invalid (non-Win32 .EXE or error in .EXE image).';
SE_ERR_ACCESSDENIED: r := 'Windows 95 only: The operating system denied access to the specified file.';
SE_ERR_ASSOCINCOMPLETE: r := 'The filename association is incomplete or invalid.';
SE_ERR_DDEBUSY: r := 'The DDE transaction could not be completed because other DDE transactions were being processed.';
SE_ERR_DDEFAIL: r := 'The DDE transaction failed.';
SE_ERR_DDETIMEOUT: r := 'The DDE transaction could not be completed because the request timed out.';
SE_ERR_DLLNOTFOUND: r := 'Windows 95 only: The specified dynamic-link library was not found.';
SE_ERR_NOASSOC: r := 'There is no application associated with the given filename extension.';
SE_ERR_OOM: r := 'Windows 95 only: There was not enough memory to complete the operation.';
SE_ERR_SHARE: r := 'A sharing violation occurred.';
else
Exit;
end;
ShowMessage(r);
end;

Utilize a função assim:


procedure TForm1.Button1Click(Sender: TObject);
begin
ExecFile('c:\windows\ladrilhos.bmp');
end;

Codificando no FastReport


Como já mencionado nos artigos anteriores o FastReport oferece um ambiente para codificação de scripts, ou seja, código este que fica contido no próprio relatório e que interage com o mesmo. 

Para demonstrar esse recurso, vamos abrir o exemplo feito no artigo passado e vamos alterar o relatório Relatorio1.fr3 para que quando o salário for menor que 60 mil Reais, o label seja impresso em vermelho. Abra o designer do fastreport e abra o modelo Relatorio1.fr3, conforme explicado nos artigo anteriores. 

Clique sobre a banda Master e pressione F11, o object inspector do FastReport vai aparecer. Entre na guia Eventos e dê um clique duplo sobre o evento OnBeforePrint. 

Automaticamente o FastReport abre o editor de código. Nesse Editor você pode escolher a linguagem do script, no nosso caso é PascalScript. 

Codifique o evento conforme mostrado na Listagem 1. 


  1. procedure MasterData1OnBeforePrint(Sender: TfrxComponent);
  2. begin
  3.   if ( < 60000) then
  4.      Memo6.Font.Color := clRed
  5.   else
  6.      Memo6.Font.Color := clBlack;
  7. end;


Listagem 1 – Evento BeforePrint 

Salve o relatório e execute a aplicação. O resultado será o visto na Figura 1. 

Clique para ver a imagem em seu tamanho real 
Figura 1. Preview do relatório 

Conclusão 

Ao utilizar o FastReport conseguimos uma flexibilidade grande na questão de relatórios. Poder escrever código no próprio relatório, independente do executável é ótimo. Fica aqui minha sugestão, espero que esta série introdutória ao FastReport tenha despertado o interesse pelo mesmo. Abraço. 

segunda-feira, 14 de agosto de 2017

Dicas para agilizar a consulta de dados em uma DBGrid

A lentidão ao carregar dados em uma DBGrid pode ser causada por vários fatores que, muitas vezes, nos passam despercebidos. As seis orientações abaixo podem ser úteis para agilizar o carregamento de dados ou, talvez, para evitar futuras lentidões.
1) Revise a instrução Select que consulta os dados
Assim como mencionei no artigo sobre práticas de otimização em banco de dados, as consultas SQL devem trazer apenas os dados que são necessários na visão da DBGrid. Por exemplo, se existem 10 colunas em uma tabela e somente 4 são exibidas em uma DBGrid, as outras 6 podem (e devem) ser retiradas da consulta. Para isso, substitua o asterisco pelas colunas requisitadas, conforme a comparação abaixo:
-- Seleciona TODAS as colunas da tabela, desnecessário na maioria das consultas
SELECT * FROM PRODUTOS
 
-- Seleciona somente as colunas necessárias para exibir os dados
SELECT Codigo, Descricao, Valor, Qtde FROM PRODUTOS
Além disso, em alguns casos, há tabelas com colunas do tipo BLOB, que armazenam dados binários de imagens e documentos ou textos longos. Se essas colunas forem adicionadas na consulta, o tempo de retorno será ainda mais demorado. A minha recomendação é trazer estes dados sob demanda em uma instrução separada, como comentei no artigo sobre eventos de tela.

2) Evite abrir e fechar o DataSet repetidas vezes
Quando for necessário aplicar um filtro nos dados, como um intervalo de datas, procure utilizar as propriedades Filter e Filtered, ao invés de comandos que fazem acesso ao banco, como CommandText, Close/OpenExecSQL. A explicação é que a propriedade Filter trabalha com dados em memória, isto é, que já foram carregados.
Entrando mais em detalhes técnicos, o ideal é substituir esses tipos de consulta:
DataSet.Close;
DataSet.CommandText := 'Select * from CLIENTES where Nome like ' + QuotedStr(Edit1.Text + '%');
DataSet.Open;
Por filtros como esse:
DataSet.Filter := 'Nome like ' + QuotedStr(Edit1.Text + '%');
DataSet.Filtered := True;

3) Atente-se aos eventos do DataSet, dos Fields e de pintura da DBGrid
Por falar em eventos de tela, o desenvolvedor também deve ser prudente ao utilizá-los, já que podem impactar no tempo de carregamento dos dados. Por exemplo, você sabia que o evento OnDrawColumnCell do componente DBGrid é chamado para cada registro que é carregado? Insira um ShowMessage neste evento, abra o DataSet e observe a quantidade de vezes que a mensagem é exibida. Logo, se houver um processamento neste evento, é evidente que os dados levarão um tempo maior para serem carregados.
A mesma orientação é válida para eventos do DataSet conectado à DBGrid, como BeforeOpenAfterOpenBeforeGetRecords e AfterGetRecords. Embora sejam executados apenas uma vez ao consultar os dados, podem apresentar lentidões se os processamentos forem extensos.
Seguindo a mesma lógica, o evento OnGetText do TField (campo da tabela), como trata a exibição dos dados de uma coluna, também é executado para cada registro e deve ser observado.

4) Adicione filtros na tela para evitar a consulta de vários registros
Muitos desenvolvedores costumam executar a consulta de dados logo quando a tela é aberta. Sendo assim, se houverem 10 mil registros, todos eles serão consultados de uma vez só! Bom, nem preciso comentar que isso é uma falha de desempenho indiscutível, não é?
Além da demora, esse procedimento também não deixa de ser uma questão de usabilidade. Muitas vezes, o usuário entra na tela para visualizar os dados de apenas 1 registro, e precisa esperar, desnecessariamente, a consulta de todos os registros da tabela.
A recomendação é disponibilizar filtros na tela (como código, descrição, tipo, período, etc…), e realizar a consulta somente quando estes filtros forem informados. Com essa alteração, já consigo apontar 3 vantagens: 1) não haverá “gargalos” ao abrir a tela; 2) o usuário visualiza somente o(s) registro(s) desejado(s); 3) reduz o tráfego de dados em um ambiente cliente/servidor.

5) Ative a paginação de registros com a propriedade PacketRecords
Quem disse que não dá para fazer paginação com Delphi? A propriedade PacketRecords do DataSet permite definir a quantidade de registros que serão “paginados”, ou carregados por vez.
Faça um teste: preencha a propriedade PacketRecords com o valor 100 e abra um DataSet que tenha aproximadamente 1000 registros. Observe que apenas 100 registros serão exibidos inicialmente na DBGrid, porém, ao navegar até a última linha, os próximos 100 registros da tabela serão carregados e exibidos automaticamente.
Este recurso pode ser bastante útil quando a tela exige a consulta de milhares de registros, por uma questão técnica ou por solicitação do cliente, ou mesmo quando a terceira dica, sobre filtros na tela, é inviável.

6) Modere na utilização de componentes de terceiros
Às vezes precisamos de algum comportamento adicional, não existente no componente TDBGrid nativo do Delphi. Como solução, normalmente instalamos componentes de terceiros para atender a nossa necessidade. No entanto, vale ressaltar que estes componentes trazem vários outros comportamentos que, em sua maior parte, pode não nos interessar no momento. Por exemplo, suponha que um componente de terceiro monte toda uma estrutura de agrupamento dinâmico, ative campos Lookup ou faça uma indexação do conteúdo para buscas, quando, o que realmente precisamos, é só um totalizador de valores no rodapé. Por estarem acoplados ao componente, estes outros comportamentos “paralelos” também podem impactar indiretamente no carregamento dos dados.
A minha sugestão é criar um novo componente herdado da classe TDBGrid e adicionar os comportamentos desejados, mesmo que exija um pouco mais de tempo. Além de dispensar a instalação de componentes de terceiros, o desenvolvedor ganha a liberdade de customizar o componente de acordo com suas próprias necessidades.

Como trocar a coluna do DBGrid de lugar


Olá, neste artigo mostrarei um forma bastante interessante de trabalhar com as colunas do DBGrid. Faremos a troca de posição das colunas usando o evento onTitleClick do DBGrid. 

Quando o usuário clicar em uma coluna esta passará a ser a primeira coluna e a primeira trocará de lugar com a coluna clicada. A primeira coluna poderia ser usada para filtrar e/ou ordenar a tabela e sendo a coluna 0 (zero) fica mais fácil para identificar por qual coluna nossa table está ordenada/filtrada. 

Desenhando o projeto 

O design para este exemplo é bem compacto. Insira um TTable, um DataSource e um DBGrid. Altere suas propriedades conformes as tabelas abaixo. Sua tela deve se parecer com a Figura 1. 

Clique para ver a imagem em seu tamanho real 
Tabela 3. Propriedades do TDbGrid 

Coluna colorida 

Uma coisa que uso com bastante freqüência é colorir a primeira coluna, assim fica ainda mais fácil identificar por qual coluna o filtro/ordenação será feito. Para isso: 

Clique duas vezes no DBGrid, adicione os todos campos. Em seguida selecione o primeiro campo, referente a primeira coluna, e mude a propriedade Color para clInfoBk ou uma cor de sua preferência. 

Clique para ver a imagem em seu tamanho real 
Figura 1. Legenda explicativa da figura 

Programação 

Você verá que a programação não exige alto conhecimento. Apenas pegamos o nome da coluna selecionada e seu index. Em seguida “dizemos” que o FieldName da colunca selecionada é igual ao FieldName da coluna 0(zero), ou seja, o primeiro campo. Agora basta igualar o FieldName da coluna zero ao FieldName da coluna selecionada. Veja a Listagem 1. 

Listagem 1. Descrição da listagem 


  1. procedure TForm1.DBGrid1TitleClick(Column: TColumn);
  2. var
  3.   nmColSel: string;
  4.   idColSel: Integer;
  5. begin
  6.   nmColSel := Column.FieldName;
  7.   idColSel := Column.Index;
  8.   with DBGrid1 do
  9.   begin
  10.     Columns[idColSel].FieldName := Columns[0].FieldName;
  11.     Columns[0].FieldName := nmColSel;
  12.   end;
  13. end;



Conclusões 

Neste artigo aprendemos a trocar a coluna de um DBGrid em runtime e tornando sua visualização mais nítida. 

Por Adriano Santos 
Adriano Santos (artes@doiscliques.com) é desenvolvedor Delphi desde 1998. Professor e programador PHP. Bacharel em Comunicação Social pela Universidade Cruzeiro do Sul, SP. É colunista e membro da Comissão Editorial da revista ClubeDelphi. 

domingo, 13 de agosto de 2017

OBTER O IMEI DE DISPOSITIVO ANDROID COM DELPHI XE5

Quando se fala de Mobilidade garantir que informações corporativas sejam visualizadas apenas por pessoal” autorizado é essencial. Nessa postagem vamos implementar a autenticação de uma aplicação
Delphi XE5 Android através do IMEI  do dispositivo.

IMEI a identificação do dispositivo IMEI  é o acrônimo de Mobile Equipment Identity (Identificação Internacional de Equipamento  Móvel). Trata-se de uma sequência de números e caracteres especiais única para cada dispositivo. A ideia é bem parecida com o  MAC address  das placas de rede. Isso facilita na hora de localizar um aparelho específico em meio às centenas de dispositivos colocados no mercado todos os meses. 

Criando a aplicação Mobile Delphi XE5

Crie um novo projeto Mobile no Delphi XE5. No fonte do form da aplicação vamos adicionar as seguintes referências na clausula uses:

uses

FMX.Platform.Android,

Androidapi.JNI.Telephony,

Androidapi.JNI.Provider ,

Androidapi.JNIBridge,

Androidapi.JNI.GraphicsContentViewText,

Androidapi.JNI.JavaTypes,

FMX.Helpers.Android;

No form vamos adicionar um Button, alterar sua propriedade Text para “Capturar  IMEI” e a Propriedade Name para btnCapturarIMEI.

Vamos codificar seu evento onClick como abaixo:

procedure

TForm1.btnCapturarIMEIClick(Sender: TObject);

var

obj: JObject;

tm: JTelephonyManager;

IMEI: String;

 begin

obj := SharedActivityContext.getSystemService(TJContext.JavaClass.TELEPHONY_SERVICE);

if

obj <> nil

then

 begin

tm := TJTelephonyManager.Wrap( (obj as

ILocalObject).GetObjectID );

if tm <> nil then
      IMEI := JStringToString(tm.getDeviceId); 
end;

if  IMEI = '' then
         IMEI:=JStringToString(TJSettings_Secure.JavaClass.getString(SharedActivity.ge  tContentResolver, TJSettings_Secure.JavaClass.ANDROID_ID));

 ShowMessage('IMEI :'+ #13 + IMEI);

end;

Fácil… extremamente fácil…

Execute a aplicação e clicando sobre o botão o IMEI do seu dispositivo será exibido.

Novas funções no Delphi XE5

  1. Novo! Compilador ARM para Android no Delphi para dispositivo e emulador
  2. Novo! Plataforma FM para a criação de aplicações nativas de Android para Gingerbread (2.3.3 – 2.3.7), Ice Cream Sandwich (4.0.3, 4.0.4) e Jelly Bean (4.1.x, 4.2.x, 4.3.x)*.
  3. Novo! Suporte e estilos do SDK do iOS 7
  4. Novo! Controle Time Picker para Android, Windows, OS X e iOS.
  5. Novo! Componente Notification Center para Android e iOS
  6. Novo! Filtragem integrada de pesquisa para TListView no Android, iOS, Windows e OS X
  7. Novo! Swipe to delete em Android e iOS
  8. Novo! Suporte a Share Sheet em Android e iOS
  9. APERFEIÇOADO! Aperfeiçoamentos de desempenho da plataforma FM
  10. Novo! Delphi RTL para Android
  11. Novo! Gerenciador de Distribuição para Android
  12. Novo! Distribua aplicações ao emulador para Ice Cream Sandwich e Jelly Bean
  13. Novo! Distribua aplicações para dispositivos Android (Debug / App Store)
  14. Novo! Depuração remota para Android
  15. Novo! A versão Professional inclui suporte FireDAC ampliado a bancos de dados locais, incluindo Microsoft Access, SQLite, InterBase ToGo / IBLite, InterBase em localhost, MySQL embutido, MySQL Server em localhost, Advantage Database local engine, PostgreSQL em localhost, Firebird embutido, e Firebird em localhost
  16. Novo! Banco de dados IBLite embutível para Android e iOS com licença gratuita de distribuição ilimitada
  17. Novo! Biblioteca REST Client para invocar serviços REST de modo simplificado
  18. Novo! Suporte de autorização, incluindo Autenticação Básica, Autenticação de Planos, OAuth1, OAuth2
  19. Novo! Componentes TRestClient, TRestRequest e TRestResponse
  20. Novo! Ferramenta de depuração REST para testar chamadas REST e seus parâmetros
  21. Novo! Seleção múltipla no Gerenciador de Distribuição
  22. Novo! IDE Insight agora disponível como caixa de pesquisa no canto superior direito do IDE
  23. APERFEIÇOADO! Gerenciador de Dispositivo para gerenciar e selecionar o dispositivo padrão no FM Mobile Form designer

quarta-feira, 26 de outubro de 2016

Descobrindo a chave do Windows 7,8,10

Execute o programa CMD como administrador e cole o comando abaixo para descobrir a chave do windows

wmic path SoftwareLicensingService get OA3xOriginalProductKey

terça-feira, 30 de agosto de 2016

Dez dicas para criar aplicações profissionais Android com Delphi XE5 e Firemonkey

Fonte TDevRocks

# 1. Salve um atalho na tela inicial depois de Instalar

Se você quer que os usuários sejam capazes de encontrar o seu aplicativo novamente depois de instalá-lo, você deve adicionar o ícone à tela inicial do usuário. O usuário pode removê-lo ou ele será automaticamente removido se desinstalar o aplicativo.

# 2. Proteger as conexões de dados do seu aplicativo com SSL

Os usuários estão se conectando a partir de hotspots públicos nos dias de hoje e você precisa proteger essas conexões de dados para manter os dados seguros. Algumas lojas de aplicativos como a Amazon App Store vai negar o seu aplicativo se você não usar conexões seguras para dados de login do seu usuário.

# 3. Criar e implantar ícones para seu aplicativo

Você vai precisar para criar um bom número de diferentes tamanhos de ícones para implantar seu aplicativo e fazer o upload para cada loja de aplicativos de for distribuir. Há um utilitário gratuito disponível, que torna isso mais fácil.

# 4. Manipular eventos de sistema Ativar e Desativar a App

Quando os usuários multitarefa usando o Android , há eventos de sistema específicos que serão disparados. Você deve adicionar esses eventos no seu aplicativo e agir conforme necessário.

# 5. Adicionar um Splash Screen App Carregando…

Apps Android podem demorar alguns segundos para carregar, onde o usuário pode ficar em dúvida sobre o que seu aplicativo está fazendo. Você pode configurar uma SplashScreen para que o usuário veja o seu logotipo ou algo semelhante enquanto carrega o seu app.

# 6. Manter o foco no controle em edição acima do teclado virtual

Quando o teclado virtual aparece por padrão ele irá cobrir a caixa que está sendo editado, se for abaixo da metade inferior da tela. Você pode rolar o formulário para que o campo que está sendo editado permaneça visível.

# 7. Use as caixas de diálogo de progresso para manter seu app responsivo

Se seu aplicativo está fazendo uma tarefa que vai levar algum tempo, como baixar ou salvar um arquivo você deve mostrar uma caixa de diálogo para o usuário com o progresso de modo que a sua aplicação não pareça congelada. Você pode usar qualquer um dos vários recursos que o Delphi te oferece.

# 8. Verifique a conectividade de rede antes de tentar ligar

Você deve verificar se o usuário está conectado à internet antes de chamar funções que necessitem conexão com a internet. Desta forma, você pode notificar o usuário se ele não tiver conectividade e seu aplicativo pode lidar com isso adequadamente.

# 9. Segurar o botão voltar do Android

Dispositivos Android tem um botão de volta o que você deve lidar para que seus usuários tenham um fluxo correto dentro de sua aplicação.

# 10. Salvar configurações entre Sessões

Você pode usar tanto TIniFile e TMemIniFile para salvar as configurações no Android assim como você faria no Windows. Tenha certeza de usar TPath.GetDocumentsPath + PathDelim para obter o local certo para salvar o arquivo INI. Uma segunda maneira de salvar as configurações seria com SQLite.

A TDevRocks fez a tradução das dicas para você, mas caso deseje ler o artigo em inglês, acesse esse link.

segunda-feira, 8 de agosto de 2016

Como copiar um arquivo em Delphi usando a função CopyFile() da API do Windows

Há situações nas quais gostaríamos de copiar um determinado arquivo. Até a versão 2009 as bibliotecas de tempo de execução do Delphi não nos fornecia uma função ou procedure para realizar tal tarefa. No entanto, é possível chamar a função CopyFile() da WinAPI a partir de nossas aplicações sem quaisquer esforços adicionais. Esta função requer o nome e caminho do arquivo a ser copiado, o nome e caminho do novo arquivo e um valor true ou false indicando se a função deve falhar caso o segundo arquivo já exista. O retorno será true se a operação for realizada com sucesso e false em caso contrário.

Veja um trecho de código no qual efetuamos a cópia de um arquivo:

procedure TForm1.Button1Click(Sender: TObject);
var
  arquivo_original, novo_arquivo: string;
begin
  // diretorio e nome do arquivo original
  arquivo_original := 'C:\arquivo de codigos\dados.txt';

  // diretorio e nome do novo arquivo
  novo_arquivo := 'C:\arquivo de codigos\dados2.txt';

  // vamos copiar o arquivo
  if CopyFile(PChar(arquivo_original), PChar(novo_arquivo), true) then
    ShowMessage('O arquivo foi copiado com sucesso')
  else
    ShowMessage('Não foi possível copiar o arquivo');
end;

segunda-feira, 11 de abril de 2016

Aprenda a executar comandos SQL usando o método ExecSQL() da classe TSQLDataSet

O método ExecSQL() da classe TSQLDataSet é usado quando queremos executar comandos SQL que não retornam um conjunto de dados. Este comando pode ser INSERT, UPDATE, DELETE, CREATE TABLE, etc, exceto SELECT.

Veja a assinatura deste método:

function ExecSQL(ExecDirect: Boolean = False): Integer; override;

ExecDirect é usado para indicar que a query não precisa ser preparada antes de ser executada. Este parâmetro pode ser definido como True se o comando não incluir nenhum parâmetro. Se o valor for False, a query será preparada antes de ser executada.

Vamos ver um exemplo? Veja um trecho de código no qual usamos o método ExecSQL() para disparar um comando SQL UPDATE. Note que aqui estamos usando um comando SQL preparado (pré-compilado):

procedure TForm3.Button1Click(Sender: TObject);
var
  nome: string;
  id: integer;
begin
  nome := 'OSMAR J. SILVA';
  id := 2; // id do registro a ser atualizado

  // vamos definir o comando SQL a ser executado
  SQLDataSet1.CommandText := 'UPDATE contatos SET nome = :nome WHERE id = :id';
  SQLDataSet1.Params[0].Name := 'nome';
  SQLDataSet1.Params[0].Value := nome;
  SQLDataSet1.Params[1].Name := 'id';
  SQLDataSet1.Params[1].Value := id;

  // como o comando é preparado, vamos definir o valor
  // False para o parâmetro ExecDirect
  SQLDataSet1.ExecSQL(False);

  // vamos mostrar uma mensagem indicando o sucesso da operação
  ShowMessage('Comando SQL executado com sucesso.');
end;

É importante observar que o método ExecSQL() retorna o número de linhas afetadas pelo comando. O valor retornado se torna o valor da propriedade RowsAffected. Veja como modificar o código anterior para retornar a quantidade de linhas afetadas:

procedure TForm3.Button1Click(Sender: TObject);
var
  nome: string;
  id: integer;
  linhasAfetadas: integer;
begin
  nome := 'OSMAR J. SILVA';
  id := 2; // id do registro a ser atualizado

  // vamos definir o comando SQL a ser executado
  SQLDataSet1.CommandText := 'UPDATE contatos SET nome = :nome WHERE id = :id';
  SQLDataSet1.Params[0].Name := 'nome';
  SQLDataSet1.Params[0].Value := nome;
  SQLDataSet1.Params[1].Name := 'id';
  SQLDataSet1.Params[1].Value := id;

  // como o comando é preparado, vamos definir o valor
  // False para o parâmetro ExecDirect
  linhasAfetadas := SQLDataSet1.ExecSQL(False);

  // vamos mostrar uma mensagem indicando o sucesso da operação
  ShowMessage('Comando SQL executado com sucesso. ' +
    IntToStr(linhasAfetadas) + ' linhas afetadas.');
end;

Lembre-se que não podemos usar ExecSQL() com comandos que retornam dados. Estes comandos incluem todos os comandos do tipo ctTable, queries SELECT e stored procedures que retornam um cursor. Quando o comando retornar dados, devemos usar o método Open ou definir a propriedade Active do SQLDataSet como True.