1) O documento discute a criação de uma tela de pré-carregamento para aplicações web usando Bootstrap e AngularJS. 2) É fornecido um tutorial passo-a-passo para adicionar AngularJS a um projeto do Visual Studio e criar uma tela de pré-carregamento com efeitos de animação. 3) O autor explica como simular o tempo de carregamento da página usando AngularJS para exibir a tela de pré-carregamento.
3. março
2015
03
21
Índice
Dicas The Club
30
Editorial
04
12
Autor: Hamden Vogel
05
Autor: Marlon Aparecido Branco Valentino
Android - criando uma tela
de login
Autor: Thiago C. Montebugnoli
Bootstrap e AngularJS
– Tela de carregamento para
aplicações web
FastFile - Aplicativo Leitor para
Arquivos Grandes
4. março
2015
04
Delphi é marca registrada da Borland International,
as demais marcas citadas são registradas
pelos seus respectivos proprietários.
Thiago Montebugnoli- Editor Chefe
thiago@theclub.com.br
Caro leitor,
Todo conhecimento adquirido hoje em dia é essencial para a for-
mação de um bom profissional, e isto se aplica principalmente em
nosso ramo de negócios. A nossa revista deste mês está mesclada
com diversos tipos de assuntos e linguagens. Começando com nosso
colunista Hamden Vogel e utilizando o Delphi como ferramenta, ele
redigiuoartigo“FastFile2.0–AplicativoLeitorparaArquivosGrandes”.
Nesta segunda versão ele implementa novas melhorias em termos de
performance dentre outros quesitos interessantes que diz respeito a
manipulaçãodedados.JáoconsultortécnicoMarlonAparecidoBran-
co Valentino continua com a saga escrevendo artigos relacionados ao
Bootstrap. Ele apresenta junto com o framework “AngularJS” uma for-
maalternativadesenvolverumatelaparacarregamentodeaplicações
Web. Para finalizar a revista, escrevi sobre um tema muito usual nas
aplicações Android, o artigo: “Android – Criando uma Tela de Login”.
Foi desenvolvido um pequeno exemplo junto com algumas classes
necessárias para o bom funcionamento, possibilitando adaptações
futuras para os sistemas escritos nesta plataforma.
Já nossa seção de Dicas tratamos de um assunto relacionado ao
Firebird junto com os componentes Firedac.
Desejo a todos uma boa leitura, um abraço e até o mês que vem!
Av. Profº Celso Ferreira da Silva, 190
Jd. Europa - Avaré - SP - CEP 18.707-150
Informações e Suporte: (14) 3732-1529
Internet
http://www.theclub.com.br
Cadastro: cadastro@theclub.com.br
Suporte: suporte@theclub.com.br
Informações: info@theclub.com.br
Skype Cadastro: theclub_cadastro
Skype Suporte: theclub_linha1
theclub_linha2
theclub_linha3
www.twitter.com/theclubbr
Copyright The Club 2013
Diretor Técnico
Marcos César Silva
Diagramação
Vitor M. Rodrigues
Design
Vitor M. Rodrigues
Revisão
Denise Blair
Colunistas
Hamden Vogel
Jeferson Silva de Lima
Luciano Pimenta
Marlon Aparecido Branco Valentino
Thiago Cavalheiro Montebugnoli
Impressão e acabamento:
GRIL - Gráfica e Editora
Taquarituba-SP - Tel. (14) 3762-1345
Reprodução
A utilização, reprodução, apropriação, armazenamento em banco
de dados, sob qualquer forma ou meio, de textos, fotos e outras
criações intelectuais em cada publicação da revista “The Club
Megazine” são terminantemente proibidos sem autorização
escrita dos titulares dos direitos autorais.
Editorial
5. março
2015
05
1- Introdução
Conforme sua aplicação vai crescendo, logo começam a aparecer os pro-
blemas de carregamento, páginas sem estilos, imagens que aparecem pela
metade, principalmenteseoaplicativonãoestiverhospedadoemumservidor
bom, enfim, uma solução para este problema seria reduzir as requisições do
http para o servidor, comprimir seus estilos CSS, suas funções JavaScript, ou
até mesmo combinar seus estilos CSS em um arquivo só e fazer o mesmo com
asfunçõesJavaScript,casonenhumadassoluçõesacimasolucioneoproblema
de carregamento, sugiro que acompanhe este artigo onde estarei ensinando
a fazer uma tela de pré-carregamento, utilizando a framework do Twitter o
BootstrapeoframworkdaGoogleoAngularJS,quevemcrescendonaáreade
desenvolvimento,principalmentedepoisdolançamentodaversãodoAndroid
Lollipop 5.0, onde ele é massivamente utilizado, mas enfim, vamos ao que
interessa, a solução para o mau carregamento de sua página.
Imagem01RespectivamenteoslogosdeTwitterBootstrapeAngularJSbyGoogle.
2- Instalando o AngularJS em seu projeto pelo Visual Studio
É muito simples instalá-lo pelo Visual Studio, com o seu projeto aberto vá
no explorador de soluções e clique com o botão direito do mouse no arquivo
chamado “References” e clique na opção “Manage NuGet Packages...”, como
é mostrado na imagem 02 logo abaixo:
Imagem 02 Adicionando AngularJS ao projeto .
Quando o gerenciador de pacotes do NuGet abrir, no canto superior
direito da tela haverá um campo de pesquisa, clique no mesmo e pesquise
“AngularJS”(aguardecarregar,poiselepodedemoraralgunssegundos),quando
carregar os pacotes, clique na segunda opção “AngularJS” e verifique ao lado
direito a versão que está, e a ultima data que foi publicada a versão, caso seja
versão 1.3.14 ou superior, clique em “Install” e aguarde a instalação, como é
feito na imagem 03.
Imagem 03 Instalando AngularJS.
Depois de instalar as bibliotecas do AngularJS, podemos ir até a pasta
Scriptsnogerenciadordesoluçõeseveremosquehaveráváriosarquivoscomo
nomedeangulareemseguidaaversão,masnesteartigo,utilizaremosapenas
oangular.min.jseoangular-animate.min.js,ambossãoarquivos“minificados”
para um melhor carregamento, neste artigo irei mostrar como adicionar o
Bootstrap e AngularJS
Teladecarregamentoparaaplicaçõesweb
6. março
2015
06
angularJS ao seu projeto pelas nuvens, note que iremos adicionar apenas a
bibliotecaprincipalenãoopacotecompletodesuasbibliotecas,ouseja,caso
acompanhe o tópico3,seránecessárioacompanhar tambémo tópico4deste
artigoparaquenofinalsuateladepré-carregamentofuncionecorretamente.
3- Continue lendo se quiser adicionar o AngularJS ao seu
projeto carregando-o diretamente das nuvens...(caso não vá
direto para o tópico 4)
Agora irei mostrar onde conseguiremos a biblioteca do angularJS dire-
tamente das nuvens para o seu projeto, que será no site “cdnjs.com”, entre
neste site e pesquise por angularJS, como mostra a imagem 04 logo abaixo:
Imagem 04 Obtendo as angularJS pelas nuvens.
logoaparecerãováriosresultados,oprimeirodeleséabibliotecaprincipal
doangular,eaopassaromousesobreaopçãoépossívelobservarquehabilitará
o botão “Copy”, clique na setinha ao lado do botão copy que ele dará a opção
para Copiar como Script Tag do html, observe como é feito na imagem 05:
Imagem 05 Copiando o código corretamente.
Depois de copiar desta forma basta colar na página mestre de projeto,
no meu caso é a _Layout.cshtml, na parte final do código antes da tag <body>
ser fechada, observe que ela fica depois da declaração do jQuery e é nesta
ordem que tem os Scripts tem que ser declarados, como é mostrado na ima-
gem 06 a seguir:
Imagem 06 Adicionando a tag <script> do AngularJS corretamente.
4-AdicionandooAngularJSaoprojetoparaqueelecarregue
localmente.
OprimeiropassoéentrarnoarquivoBundlesConfig.cs,ondesãodeclara-
dos todos os Scripts e estilos do seu projeto a serem carregados localmente,
o que já comentei em artigos anteriores sobre o bootstrap com Razor e MVC,
enfim, ao abrir o arquivo de pacotes será necessário ir até o final do código e
criar um novo pacote de Scripts, declarando a biblioteca principal do angular.
min.js (OBS: se acompanhou o tópico 3 desconsidere adicionar a angular.min.
js) e a angular-animate.min.js, ou basta copiar o código abaixo:
bundles.Add(new ScriptBundle(“~/
bundles/angularjs”)
.Include(“~/Scripts/angular.
min.js”,
“~/Scripts/angular-
animate.min.js”));
DepoisdecriaronovopacoteparaoAngularJS,váatéapáginamestrede
projeto, caso tenha dúvidas observe como é feito na imagem 07:
Imagem 07 Declarando o pacote na página mestre.
5- Escolhendo a tela de pré-carregamento ideal para o seu
projeto.
Quando finalizar a declaração do AngularJS em seu projeto, vamos es-
colher qual a tela de pré-carregamento ideal a será exibida, para isso iremos
utilizar um recurso gratuito chamado Spinkit, nele você escolhe uma das 8
opções disponíveis e copia o código fonte da escolhida, para fazer isso siga os
passos deste tópico, para começar entre no site:
http://tobiasahlin.com/spinkit/
Para o projeto do artigo escolhi a terceira opção, depois de escolher a
tela de carregamento, clique na parte superior do site onde está escrito “<>
Source” como é exibido na imagem 08.
7. março
2015
07
Imagem 08 Obtendo o código fonte da tela de pré-carregamento.
Ao clicar em “<> Source” será exibido um modal com o código HTML e o
CSS da tela de pré-carregamento, observe na imagem 09.
Imagem 09 Diferenciando os códigos.
6- Adicionando a tela de pré-carregamento ao projeto.
Copie todo o código HTML que fica parte superior do modal, e vá até o
Visual Studio na página mestre de seu projeto e cole-o logo abaixo do inicio
da tag <body>, como é exibido na imagem 10:
Imagem 10 Adicionando o código HTML ao projeto.
AgoraseránecessáriocriarumarquivodeestilosparacolocarocódigoCSS
disponibilizadopelositedo“spinkit”,parafazê-lobastairatéoseuexplorador
de soluções, localizar a pasta “Content” de seu projeto e clicar com o botão
direitoemcimadamesma,iremAdddepoiscliqueemStyleSheet,damesma
forma que é mostrado na imagem 11 logo abaixo:
Imagem 12 Criando um estilo para o código fonte da tela de pré-carregamento.
Ao abrir a tela para nomear o arquivo digite “spinner” e clique em OK,
depois disso arquivo será aberto imediatamente, basta apagar os códigos
padrão que o Visual Studio gera, e colar o código CSS copiado do “spinkit”,
salve-o e feche-o. Agora iremos declará-lo no arquivo BundlesConfig.cs, abra
omesmo,elocalizeoStyleBundle(pacotedeestilos)comonomedeContent/
css,eadicioneocaminhodospinner.css,bastacolocarumavírgulanafrentedo
ultimo e digitar o caminho entre aspas duplas, como é feito no código abaixo:
bundles.Add(new StyleBundle(“~/
Content/css”).Include(
“~/
Content/bootstrap-theme.css”,
“~/
Content/site.css”,
“~/
Content/spinner.css”));
7- Começando a escrever a função que dará vida a tela de
carregamento.
8. março
2015
08
OBS:Quandoestiverlendoesteartigo,provavelmenteesteprojeto
já estará disponibilizado no site do TheClub para download, recomendo
que vá até o site e realize o download do arquivo, pois neste artigo não
explicarei como é o funcionamento de cada uma e a lógica, o que não é
oobjetivodomesmo,eparaqueménovoemAngularJSrecomendoque
copie o procure um tutorial rápido, apenas para entender como é feita
a declaração da aplicação no AngularJS, e de seus controladores, logo a
compreensão manipulação dos códigos disponibilizados para download
será muito mais fácil.
ParacomeçarcriaremosumarquivoJavaScriptdentrodapastaScriptsdo
projeto, como nome de “angular-funcoes”, vá até o explorador de soluções
e clique com o botão direito em cima da pasta Scripts, siga por Add depois
JavaScript file, como é feito na imagem 13:
Imagem 13 Adicionando ao projeto o arquivo JavaScript para as funções do
AngularJS.
Ao abrir o arquivo, copie o código abaixo contendo todas as funções:
/* Criando um módulo de
aplicação para o aplicativo,
observe que o nome AppTheClub
é o nome que defini para o meu
aplicativo.*/
var app = angular.
module(“AppTheClub”,
[“ngAnimate”]);
/*SIMULANDO A LATENCIA
DA INTERNET E O TEMPO DE
CARREGAMENTO. Note que não irei
declarar o ngApp no inicio da
página mestre do projeto pois
iremos inciá-lo nesta função,
que também da vida a nossa tela
de carregamento:*/
setTimeout(
function asyncBootstrap() {
angular.
bootstrap(document,
[“AppTheClub”]);
},
(3 * 1000)//basta trocar
o 3 para aumentar o
//tempo que a tela
de pré-carregamento
//é exibida.
);
/* Esta função controla
a raiz da aplicação, ela
apenas exibe uma mensagem no
Console do navegador dizendo
que o aplicativo carregou
corretamente:*/
app.controller(
“AppController”,
function ($scope) {
console.log(“Aplicativo
Carregado! “, $scope);
}
);
/* Esta classe CSS controla o
efeito que anima a tela de pré-
carregamento quando ela termina
de carregar:*/
app.directive(
“mAppLoading”,
function ($animate) {
return ({
link: link,
restrict: “C”
});
/* Esta função vincula os
eventos JavaScript ao scope.*/
function link(scope,
element, attributes) {
/* NOTE: Estou
utilizando o .eq(1) para não
estilizar o Style block.*/
$animate.
leave(element.children().
eq(1)).then(
function
cleanupAfterAnimation() {
element.
remove();
scope =
element = attributes = null;
});}});
9. março
2015
09
8- Adicionando o Script do AngularJS ao projeto pelo Bun-
dlesConfig.
Agorasalveefecheoarquivo,váatéoBundleConfig.cselocalizeocódigo
ondedeclaramosoAngularJSanteriormenteeadicioneocaminhodoarquivo
que acabamos de declarar, o angular-funcoes.js, basta colocar uma virgula e
colocar o caminho entre aspas duplas como é feito no código abaixo:
bundles.Add(new ScriptBundle(“~/
bundles/angularjs”)
.Include(“~/Scripts/
angular.min.js”,
“~/
Scripts/angular-animate.min.
js”,
“~/
Scripts/angular-funcoes.js”));
9- Adicionando o código necessário a página mestre para o
funcionamento da tela de pré-carregamento.
OBS:O código citado a seguir estará disponível no site do TheClub
para download, mesmo com o código em mãos, siga este tópico pois
estará explicando a sintaxe correta do código na página mestre.
Ao finalizar, salve as alterações e feche o arquivo, em seguida abra
a página mestre do projeto, no meu caso é a _Layout.cshtml, agora ire-
mos começar a trabalhar nesta tela, o primeiro passo é declarar o nosso
controlador do angularJS na tag body, como mostra o código abaixo:
<body ng-
controller=”AppController”>
Agora também escreveremos o código CSS (Style) que dará vida a nossa
tela de carregamento, para isso teremos que criar uma nova <div> e na tag de
aberturadadiretiva(adiv),seránecessáriodeclararaclassequeutilizamosna
função angularJS que escrevemos anteriormente, e na frente a referencia do
Styleblockdonossocontainer,destaformaquandooaplicativoforcarregadoe
ocontainer(ateladecarregamento)forremovidadatela,eleautomaticamente
será removido da DOM, , dentro da diretiva que acabamos de criar, declare
uma tag <style> e feche, copie o código a seguir para dentro da tag style:
<div class=”m-app-loading” ng-
animate-children>
<style type=”text/css”>
div.m-app-loading {
position: fixed;
/* Utilizado para definir as
propriedades do final do estado
de animação do ng-leave do
angularJS.*/
div.m-app-loading div.animated-
container.ng-leave-active {
opacity: 0;
}
div.m-app-loading div.messaging
{
color:
#FFFFFF;
font-
family: monospace;
left: 0px;
position:
absolute;
right: 0px;
text-align:
center;
top: 50%;
margin:
0 auto; /*Esta propriedade
centraliza a tela de
carregamento.*/
text-align:
left;
}
div.m-app-loading h1 {
font-size:
26px;
line-
height: 35px;
margin: 0px
0px 20px 0px;
}
div.m-app-loading p {
font-size:
18px;
line-
height: 14px;
margin: 0px
0px 0px 0px;
}
</style>
Em seguida abra uma outra tag <div>, ainda dentro da que criamos, logo
abaixo do style que acabamos de escrever, colocando o código que copiamos
dositespinkit(fontedateladecarregamento)dentrodela,oubastarecortá-lo
10. março
2015
10
e colá-lo dentro da diretiva, e na tag de abertura da diretiva será necessário
declarar a classe que é utilizada para dar vida a tela de pré-carregamento,
observe como é feito no código:
@* Esta <div> que criamos para
declarar a classe declarada no
style acima. *@
<div class=”animated-
container”>
@*Este é o inicio do código que
copiei do spinkit*@
<div class=”messaging
spinner” >
@* É necessário adicionar a
classe “messaging” antes da
classe spinner*@
<div
class=”rect1”></div>
<div
class=”rect2”></div>
<div
class=”rect3”></div>
<div
class=”rect4”></div>
<div
class=”rect5”></div>
</div>
</div>
Enfimpodemoscompilaroprojetoeverificarofuncionamento,oresultado
que obtive é exibido na imagem 14 logo abaixo:
Figura 14: Tela de pré-carregamento funcionando.
Três segundos depois a tela desaparece, exibindo assim a tela principal
do projeto completamente carregada, tenha em mente que esta tela de car-
regamento será exibida em todas as telas do projeto, já que a declaramos na
página mestre, ou seja, todas as suas páginas descendentes herdarão a tela
de pré carregamento.
10-Comoalteraracordoefeitodepré-carregamentoecomo
obteracoridealatravésdo“colorpicker”(selecionadordecores)
do Visual Studio.
Neste aposto que muitos estão se perguntando “Como faço para alterar
as core da tela de pré-carregamento?”, bom é muito simples, vamos começar
peloefeito,bastaacessaroarquivospinner.cssquecriamos,encontraraclasse
ondeestádeclaradoostylebackground-color,nafrentedeleédeclaradaacor,
observe que ela começa com um hash “#” e em seguida 6 carácteres, entre
letras e números, caros leitores este é o formato hexadecimal, caso não seja
familiarizado com o formato, basta apagar os 6 caracteres após o hash(#) e
apertar Ctrl + Space que o Visual Studio abrirá o colorpicker(selecionador de
cores) com algumas cores aleatórias, veja como é feito na imagem 15:
Imagem 15 Abrindo o colorpicker do Visual Studio.
Mas isso não é tudo, se a cor desejada não está entre elas, não fique
chateado, basta clicar no botão ao canto direito do colorpicker exibido, e será
exibida a ferramenta para selecionar a as cores uma cor.
Após habilitá-lo observe na parte de baixo, ao lado esquerdo tem a
opção “Opacity”(opacidade) que altera a opacidade da cor, movendo o nível
de opacidade para a esquerda você deixa a cor menos opaca, deixando-o no
máximoacorficacomaopacidadenormal(semtransparência),utilizandoesta
opção o código de cor e alterado para o tipo “rgba” que possibilita alterar a
opacidade da cor, já o hexadecimal não possibilita utilizar este recurso, veja
a imagem 16 logo abaixo:
Imagem 16 Demonstrando o como utilizar os recursos do colorpicker do Visual
Studio.
Agoravocêdeveestarseperguntando“Paraqueserveobotãonocantoin-
feriordireito?”,aquelebotãoumrecursoparaselecionarateladoseudesktop,
ou seja, basta você passar o mouse em cima de alguma cor que deseja obter
de seu desktop e clicar nela, para exemplificar a que obtive foi a do ícone do
próprio Visual Studio(código hexadecimal #68217a).
11. março
2015
11
Assim que alterar a cor do efeito da tela de pré-carregamento, é possível
mudar o plano de fundo dela também, para dar um melhor contraste no mo-
mentodaexibiçãodatela,nomeucaso,invertiascores,coloqueiacordologo
doVisualStudiocomoplanodefundoedeixeiadoefeitocomobranco(código
hexadecimal da cor branca é #FFF).
Paraalteraracordoplanodefundováatéapáginamestredeseuprojeto,
e vá até a segunda classe que declaramos e localize o style de background-
-color, como foi feito anteriormente, apague os dígitos depois do hash(#) e
pressione Ctrl + Space, e selecione a cor desejada, para se localizar melhor
observe a imagem 17:
Imagem 17 Alterando a cor do plano de fundo da tela de pré-carregamento.
O Resultado obtido é o exibido na imagem 18 logo abaixo:
suporte@theclub.com.br
Marlon Aparecido Branco Valentino
jovemdesenvolvedorfront-end,comconhecimentonaslingua-
gensHTML5,CSS3,JavaScript,enasframeworksjQuery,Bootstrap,
AngularJS e suas demais bibliotecas.
Sobre o autor
Imagem 18 Resultado obtido após a alteração da cor com o colorpicker
do Visual Studio.
Conclusão
Neste artigo demostrei uma maneira bem fácil de se criar uma tela de
pré-carregamentoparaasuaaplicaçãoemAngularJS,etambémalgumasdicas
paraconheceresteframeworkquevemcrescendoaolongodosúltimosanos.
Neste tutorial não utilizamos o “.fadeOut()” do jQuery que é o mais utilizado
para este efeito, e sim o “$animate” do AngularJS, uma forma alternativa
para o desenvolvedor que necessita implementar estes recursos em suas
aplicações Web.
Espero que tenham gostado, até a próxima!
12. março
2015
12
Caros leitores, esta é a segunda versão do nosso aplicativo relatado na
edição anterior. O que temos são inúmeras melhorias em termos de perfor-
mancedentreoutrosquesitosinteressantesnoquedizrespeitoamanipulação
dos dados, linha a linha.
Porque ler um arquivo grande?
Existem muitas situações em que precisamos ler um arquivo grande, seja
binário ou texto, muito utilizado para cargas em bancos, processamentos di-
versos,etc;edessamaneiranegocialmentepodeterumaltocusto,degrande
valia para ele; não se pode perder seus dados tampouco indisponibilizar o
aplicativo com erros de falta de memória. E isso é muito fácil de acontecer, a
medida em que o arquivo cresce os erros também aumentam nesse sentido
– é uma proporção que acompanha e ilustra esse cenário – e então, como
resolver?Qualamelhorformadeabrirarquivosgrandesemostrarelesnatela?
Venho trazer uma solução otimizada – o aplicativo FastFile agora em sua
versão 2.0.
Muitas mudanças aconteceram, e o mais importante é que todo proces-
samento do arquivo se fará de forma rápida e elegante – multithread – e sem
mais problemas de memória.
Separarprapensar,constataráqueasalternativasencontradasnainternet
sãoumtantodesanimadoras–experimenteutilizaralternativascomo“Memory
Mapping Files”, por exemplo. Sua aplicação vai lançar uma exceção do tipo
“OutOfMemory”eencerraroprograma.Demaisalternativascomoobjetosdo
tipo TStringList ou até do tipo TMemoryStream também darão o erro seme-
lhante–etefrustarão–nenhumdelesvaiabrirecarregaroarquivo. Poderão
até tentar, mas vão parar em algum ponto e abortarão o seu procedimento/
função de carregamento do arquivo.
Nossoaplicativopodedemoraratéalgunssegundosamaispraresponder,
porém dar erros de falta de memória será muito raro. Claro que muita coisa
conta; vamos aos fatos:
Razões para tornar mais lenta a leitura dos arquivos:
1. Se a leitura for repetida inúmeras vezes com arquivos grandes;
FastFile 2.0 – Aplicativo
Leitor para Arquivos Grandes
2. Muitas janelas abertas simultaneamente com cada uma represen-
tando aplicativos consumindo muita memória ao mesmo tempo;
3. Abrir mais de um FastFile ao mesmo tempo e executando os itens
acima;
4. Como dito anteriormente, requisitos de hardware/software infe-
riores ao recomendável (memória inferior a 3 GB/RAM, por exemplo);
5. Pouco espaço em disco;
6. Antivírus que interfira no processo.
Nestarevisãodoprograma,emsuaversão2.0,muitascoisasforam
revisadas e quase que 100% reescrito – o resultado impressiona. Além
de ler e carregar o arquivo inteiro de mais de um 1GB em 20 segundos
(em média) – serão mostradas duas alternativas de que “existe luz no
fim do túnel” – e esperançosamente com a própria VCL – sem nenhum
componenteadicionalaonossoaplicativo.Anovidadeéexplorarrecur-
sosdeextraçãodepartesviaTMemoryStreameexibi-losinteiramente
emumTListViewvirtualetambématravésdeumTClientDataSetaces-
sadoviamultithread,salvandoemumcampodotipoftBlobeindexado
– assim o arquivo pesado será aberto, lido e carregado sem nenhum
problema!Aprimeiraalternativa(TListView)éamaisrecomendávelpor
sermaisvelozemenospropensaaerrosdoqueasegunda.Oprograma
vai carregar todo o conteúdo de arquivos “gigantes” (testado com até
1.2 GB de tamanho) – mas poderá ser avaliado com arquivos maiores
ainda do que este – depende muito da memória do computador em
questão bem como a velocidade do processador, e não por último a
capacidade do HD disponível.
Recomendações Iniciais
Este aplicativo requer algumas configurações básicas para melhor per-
formance. São estes fatores em que foram testadas – e é principalmente esta
configuração de hardware que deve ser levado em conta.
1. Memória Mínima 3GB RAM (testada e recomendada: 4GB RAM);
2. Espaço HD – mínimo 15 GB;
3. Velocidade Processador 2.50 GHz
4. Permissão de leitura e gravação do diretório onde o arquivo se
encontra.
13. março
2015
13
Criação do Cenário – Primeira Alternativa
Agoravamosexplicarcomovaiseronossoambiente.Eécomoserálidoo
arquivo.Eleserálidoparteporparte–teremosumobjetochamadoStrmInput
(TFileStream) que apenas criará o arquivo no nosso programa – e assim será
lido parte por parte sequencialmente, através de um valor que define auto-
maticamente o tamanho de cada parte (implementadas em um algoritmo
próprio–nossafunçãoNumberOfPartsToDivide)ondeporsuavezrepresenta
ototaldepartesaseremlidas,relação“tamanhooriginaldoarquivo/tamanho
padrão de cada parte = número de partes a serem lidas”.
Por exemplo, um arquivo contendo 455872375 bytes será gerado o ta-
manho de cada parte de 455900 bytes, onde a quantidade de partes é 1000
(455872375/455900=999,9394055713972=>arredondamentode1000).No
nosso caso o arquivo se chama “loadfile03.txt” e apresenta o tamanho (de
acordo com o MsExplorer) de 445.188 KB (em bytes – 455872375).
Cálculo:
Observação:
Leia-secomprimentoetamanho–termosidênticosparaaexemplificação
do processo.
Descrição:
Em fração, o denominador corresponderá a quantidade de partes exatas
em que será dividido o arquivo, enquanto que o numerador será o tamanho
do arquivo.
Variáveis envolvidas:
Numerador e Denominador.
Fórmula Intermediária:
Numerador:
Corresponde ao tamanho original do arquivo, em bytes.
Denominador:
Base10elevadaaoexpoente(comprimentodoarquivooriginal–compri-
mento arredondado do arquivo original dividido por 2) – onde se o compri-
mento do arquivo for de 1 e 2 será auto-definido por 4 e 8, respectivamente.
Portanto, denominador será 10tamanho arquivo original – tamanho div/2.
Fórmula Final:
Arredondamento (Numerador/Denominador) * 100.
Com isso, será retornado o valor padrão do tamanho de cada parte a ser
dividida.Quantomaioroarquivo,maiorotamanhodecadaparteaserdividida
(proporcionalmente à fórmula gerada).
Segue abaixo trecho do código-fonte da implementação da função Num-
berOfPartsToDivide:
function TfrmMain.
NumberOfPartsToDivide(const
filesize: integer): integer;
var
denominator: integer;
{ In fraction, the
denominator will match the
amount of exact parts where the
file will be divided,
while the numerator is
the file size.
Em fração, o denominador
corresponderá a quantidade
de partes exatas em que será
dividido o arquivo,
enquanto que o numerador
será o tamanho do arquivo. }
begin
case length(IntToStr(Round(fil
esize))) of //convert to bytes
1: denominator := 4;
2: denominator := 8;
else
denominator :=
Round(Math.Power(10,
length(IntToStr(filesize)) - Rou
nd(length(IntToStr(filesize)) /
2)));
end;
Result := Round(filesize/
denominator) * 100;
end;
A parte gerada de um arquivo (chamada PartFileSize) será sempre a
diferença entre o tamanho total do memoryStream utilizado (size) menos a
posição atual (position) – sempre verificado antes se o tamanho total menos
a posição atual é menor que esta parte gerada, como podemos ver no trecho
seguinte abaixo:
StrmInput := TFileStream.
Create(StrFilename,fmOpenRead
or fmShareDenyNone);
try
{…}
while (StrmInput.Position <
StrmInput.Size) and (Tag = 0)
do
begin
StrmOutput := TMemoryStream.
Create;
try
if StrmInput.
Size - StrmInput.Position <
PartFileSize then
PartFileSize :=
StrmInput.Size - StrmInput.
Position;
14. março
2015
14
StrmOutput.
CopyFrom(StrmInput,PartFileSi
ze);
finally
FreeAndNil(StrmOutput);
End;
{ …}
Finally
FreeAndNil(StrmInput);
end;
Figura 01 – Diretório dos arquivos texto utilizados no FastFile.
Processamento do Arquivo – Primeira Alternativa
Esta primeira alternativa na minha opinião é a melhor de ambas – utiliza
recursos da classe TThreadList , que é uma lista de Threads, chamando nossa
implementaçãoparticulardeTList– FLineReaderList–inserindonelaaslinhas
(número e conteúdo de cada uma) e também para incrementar uma variável
contadora chamada Counter (definida em TMyObject) .
A estrutura de leitura linha a linha: TLineReader
AclasseTLineReaderrepresentanossaexcelênciadesoluçãodeleiturade
cada linha do arquivo desejado. Essa leitura será feita extremamente rápida,
porserimplementadaemumaclasseTLineReaderList (TList)–ondecadaitem
desta classe referenciará internamente os objetos de TLineReader.
Funciona assim:
1. TMyObject é a classe que implementa um contador global;
2. TLineReader implementa leitura por linha (que vai ler parte por
parte do arquivo);
3. TLineReaderListimplementaumconjuntodeTLineReader,herdando
do tipo TList;
4. TThreadList é a lista de threads que chamará TMyObject, obterá
o contador atual, e incluirá na nossa lista TLineReaderList as referências de
TLineReader nela;
5. O contador Counter de TMyObject é incrementado juntamente
com a nossa variável global lineCounter;
6. É feito o sincronismo com a VCL através de um objeto progressbar
(TProgressBar)parareportaràtelaoandamentodaexecuçãodestaoperação;
7. Após essa etapa todos os dados da estrutura TLineReaderList
estarão disponíveis para o nosso TListView, apresentando rapidamente sob
demandatodasasqueforemrequisitadasporeledinamicamente.Enãohaverá
problema de memória para esta operação.
A classe TLineReaderList é importante para o nosso processamento do
arquivo; como ela herda de TList (que é uma lista de ponteiros) – ela lerá todo
oconteúdodoarquivodesejado–linhaalinha,armazenandooiddalinhaeo
conteúdo desta id – cada id representará uma linha em si – implementamos a
função GetItem utilizada para a propriedade da coleção Items em
property Items[Index: Integer]: TLineReader read GetItem; default; por-
tanto segue o código-fonte abaixo que declara nossas estruturas de leitura
de linhas de arquivo:
//class to implement a “global
counter” used for its connected
threads
type
TMyObject = class
private
Counter: integer;
public
constructor Create(const
iCounter: integer);
end;
var
ThreadList: TThreadList;
// The line class definition
type
TLineReader = class
private
FContents: string;
FLine: Integer;
public
// Properties to read these
data values
property Contents: string
read FContents write FContents;
property Line: Integer read
FLine write FLine;
// Constructor
constructor Create(const
AContents: string; const ALine:
Integer);
end;
// The typed list of
TLineReader objects
TLineReaderList = class(TList)
private
function GetItem(Index:
Integer): TLineReader;
15. março
2015
15
public
property Items[Index:
Integer]: TLineReader read
GetItem; default;
end;
Descrição do Processo de Leitura – Passo a Passo
Assim sendo, cada parte dividida pelo programa será lido linha a linha
por esta estrutura.
1. O programa carregará o arquivo;
2. O programa dividirá o arquivo em várias partes pré-definidas por
ele mesmo;
3. Para cada parte dividida será disparada uma thread para ela, que
por sua vez terá o objetivo de ler cada linha destas partes divididas;
4. Apenasumathreadporvezvaigravarnaestruturadelista TLineRe-
aderList o id e o conteúdo das linhas, para que não ocorra acesso simultâneo
entre elas e consequentemente violação de acesso;
5. Após o processamento da leitura de todas as partes, constituídas
por todas as suas threads (cada parte tem a sua thread) a nossa função de
processamento chamará um objeto da classe TListView em modo virtual – e
é aqui onde a brincadeira começa.
OobjetodeTListViewimprimiráosdadosdasleituras,linhaalinha,natela
doaplicativo,sendorenderizadodinamicamenteporumobjetodotipoTScroll-
Bar. E a velocidade é extremamente rápida – por ser virtual o nosso TListView
não armazena os dados em si, ela depende de uma estrutura auxiliar que os
armazene – e é aqui onde entra nossa estrutura TLineReaderList, que como
já foi dito, é baseada em TList, portanto é baseada em lista de ponteiros – o
que temos aqui é armazenamento de milhões de linhas em poucos segundos
– uma média de 20 segundos para leitura integral de um arquivo de 1,2 GB. E
sem “travar” a tela, lançar exceções de memória insuficiente ou coisa assim.
Há a certeza de que o caminho feliz do fluxo chegará com sucesso e podemos
repetir a operação quantas vezes forem necessárias – todos os objetos da
lista serão removidos e destruídos (com a memória desalocada) como em:
“for i := 0 to
FLineReaderList.Count - 1 do
TObject(FLineReaderList[I]).
Free;”
“FreeAndNil(FLineReaderList);”
ListView Virtual
UmobjetodeTListViewéumobjetoextremamenteútil.Podesecomportar
de varias formas, isto é, tem vários tipos de visualização, formatação, etc. A
lista de arquivos do MsWindowsExplorer é um objeto de TListView.
OcomponenteTListViewéumencapsulamentodocomponenteListView
doWindows.Eleémuitointeressantenoquedizrespeitoasuaflexibilidadede
customização, podendo por exemplo utilizar o estilo de visualização “ViewS-
tyle” como “vsList”,“vsReport”, etc; dentre outras inúmeras possibilidades. É
um componente que pode ser utilizado como um contêiner para o recordset
de uma consulta de um banco de dados, respostas de uma procura de itens
de arquivos resultantes de TSearchRec, dentre outras mil opções disponíveis.
Porisso,suautilizaçãoémuitosatisfatória,podendosubstituircomponen-
tes como TDBGrid e TStringGrid sempre que possível; bastando implementar
eventos necessários para o CRUD (Create/Read/Update/Delete) do dataset
desejado, mas também é tranquila sua adaptação.
O problema é a quantidade de registros que deseja mostrar nele. Só isso.
Sedesejamosmostrarummilhãoderegistros,porexemplo,vaitravar!Seráum
problema e sua aplicação ficará com a tela “congelada” podendo dar também
erros de falta de memória, memória insuficiente, etc; o que fazer nesse caso?
Como resolver se os dados são muito volumosos?
A resposta é a seguinte: Use um TListView virtual.
Aínessecasotudovaimelhorar,poisnossoobjetodeTListViewapenasvai
solicitarositensquedesejamostrar,aumentandomuitoavelocidadedeapre-
sentação.IssoaconteceporqueoobjetodeTListViewvirtualnãoéproprietária
deseusitens.Elanãosabeoqueelaguardadentrodesimesma.Enaverdade
elanãoguardamesmo,quemvaiguardarvaiserumaestruturaauxiliardentro
dela que dará esse suporte. Essa estrutura é o programador quem vai decidir
o que vai escolher, pois existem milhares de opções. Ele vai sobreescrever o
evento OnData dela, que é o evento utilizado para renderizar linha a linha
deste TListView apresentado. Então, todos os dados vão ser carregados por
esta estrutura e exibido em tempo de execução “sob demanda” – ou seja –
sempre que o usuário solicitar, linha a linha, estes dados são desenhados no
momentoemquesãovisualizados–enãotodosdeumasóvez–comoseriase
fossenão-virtual(omodotradicional).Avantageméavelocidadeadmirávelde
renderização – e não custa memória, pois no nosso caso empregaremos uma
estrutura baseada em TList – que quer dizer, uma lista baseada em ponteiros.
TListéumalista(coleção)deobjetos,acessívelporumíndice,ondeesteíndice
retornademaisatributosdesteobjetorelacionadodentrodela,podendocriar
novos objetos, alterar, remover, etc; pode-se limpar a lista inteira e até inserir
objetos nulos (nil) dentro dela. Pode-se também definir e recuperar valores
(set/get,respectivamente)utilizandoaindexaçãodoarrayItemsdela.Ouseja,
é muito importante sua utilização, porque como é referenciada diretamente
na memória, ela é muito rápida.
Figura 02 – Template de um exemplo de TListView virtual
Segue abaixo um exemplo de fonte de como gerar alguns registros dina-
micamente,paradentrodenossaestruturaauxiliar(TLineReaderList)quefará
o papel de “suporte de armazenamento auxiliar” para a renderização virtual
de nosso objeto de TListView:
16. março
2015
16
procedure TForm1.
Button1Click(Sender: TObject);
var
i: integer;
totalItens: integer;
begin
// MyList := TList.Create;
counter := 0;
FLineReaderList :=
TLineReaderList.Create;
totalItens := 5000;
ProgressBar.Max := totalItens;
ProgressBar.Position := 0;
for i := 0 to totalItens do
begin
// MyList.Add(pinteger(i));
FLineReaderList.
Add(TLineReader.Create(‘Added
new item’, i));
ProgressBar.Position :=
ProgressBar.Position + 1;
Application.ProcessMessages;
end;
ListView1.OnData :=
ListView1_Data;
ListView1.Refresh;
ShowMessage(‘pronto’);
end;
Deacordocomocódigoacima,arenderizaçãoseráfeitaautomaticamente
porqueoobjetodeTListViewsaberáoquebuscarnahoradeexibirosdados–
nemtudoémostradoaomesmotempo,mas“sobdemanda”,ouseja,amedida
em que as linhas são exibidas para o usuário o componente se encarrega de
chamar nossa estrutura auxiliar de apoio para mostrar os dados em seu lugar
– e dessa forma os dados são apresentados de forma dinâmica – e o que isso
significa? Mais rapidez de exibição dos dados. Lembre-se sempre de utilizar
o evento OnData dele, pois é lá que nossa estrutura auxiliar TLineReaderList
será chamada linha a linha, conforme código abaixo:
procedure TfrmMain.ListView1_
Data(Sender: TObject; Item:
TListItem);
function getLineContentsFromLi
neIndex(const iLine: integer):
string;
begin
Result := ‘-’;
if (iLine >= 0) and (iLine <
FLineReaderList.Count) then
Result := (FLineReaderList.
Items[iLine].Contents);
end;
var
Index: Int64;
begin
// Item.Index now represents
an offset from an offset,
adding them together
// gives the true index
Index := Offset + Item.Index;
Item.Caption := ‘Line: ‘ +
IntToStr(Index) + ‘ ‘ + getLin
eContentsFromLineIndex(Index);
end;
Assim sendo, a função getLineContentsFromLineIndex retorna sempre o
conteúdo atual de TLineReaderList (FLineReaderList.Items[iLine].Contents) –
chamadolinhaalinhapeloTListViewvirtual.Reparenosparâmetrosdoevento
OnData(Sender:TObject;Item:TListItem)–osegundoparâmetroéoíndiceda
linha! E ele fará referência à nossa função – chamando linha por linha – mas
nossaestruturaébaseadaemTList–entãonãohaveráproblema–émemória
pura, rapidez garantida na resposta. Fazendo um teste de performance, se
inicializássemos nosso objeto de TListView como ItemCount := High(Int64)
teríamosemmenosdeumsegundoacompilaçãoapresentandoarenderização
dinâmica de todas as linhas criadas de 0 até 9223372036854775807 linhas!
Figura 03 – Teste de apresentação da renderização das linhas em modo virtual,
intervalo de 0 a 9223372036854775807 linhas (High(Int64)).
Figura 04 – Teste de apresentação da renderização das linhas em modo virtual,
17. março
2015
17
intervalo de 0 a 9223372036854775807 linhas (High(Int64)).
Apresentação dos dados - ListView Virtual no FastFile
O nosso objeto de TListView vai exibir os dados no final, quando o objeto
de TProgressBar finalizar a contagem das partes lidas do arquivo. Para cada
parte será chamada uma thread para lê-la, conforme já dito anteriormente:
1. Parte do arquivo gerada;
2. TFileSaveThread criada para ler a parte;
3. Objeto de TStringList para ler o conteúdo total da parte;
4. Loop no objeto de TStringList para acrescentar cada item dele
na estrutura FLineReaderList (frmMain.FLineReaderList.Add(TLineReader.
Create(strList.Strings[i], obj.Counter));
5. Definir a quantidade de linhas no TListView conforme nosso con-
tador global atualizado entre as threads (sincronismo) – como em ListView1.
Items.Count := Min(ItemCount, lineCounter);
6. Exibir o objeto de TListView virtual na aplicação.
Figuras 05 e 06 – Exibição do FastFile com o arquivo carregado – no teste um
arquivo texto de carga chamado “LoadFile05.txt” com o tamanho de 1.284.808 KB,
carregado em 24 segundos, com o objeto de TListView em modo virtual renderizando
um total de 11064232 linhas.
Associação com objeto TScrollbar
O nosso objeto de TListView não vai exibir tudo ao mesmo tempo, como
já sabemos. O que muda aqui é como o sincronismo entre os dados e sua exi-
bição é controlado – não há o suporte direto de barras de rolagem – estamos
no modo virtual - quem vai fazer esse papel é um objeto da classe TScrollbar.
Para que isso realmente tenha eficiência, precisamos realizar a troca de
informaçõesentreaslinhasdoTListViewcomoeventoOnScrolldoTScrollbar.
Segue código-fonte abaixo de como isso será feito.
procedure TfrmMain.
ScrollBar1Scroll(Sender:
TObject;
ScrollCode: TScrollCode; var
ScrollPos: Integer);
var
MaxOffset: Int64;
begin
// Int64 support for
scrollbar, etc
MaxOffset := ItemCount -
VisibleItems + 1;
case ScrollCode of
scLineUp: begin
if Offset > 0 then
Offset := Offset - 1;
end;
scLineDown: begin
if Offset < MaxOffset
then
Offset := Offset + 1;
end;
scPageUp: begin
if Offset > VisibleItems
then
Offset := Offset -
VisibleItems
else
Offset := 0;
end;
scPageDown: begin
if (MaxOffset - Offset) >
VisibleItems then
Offset := Offset +
VisibleItems
else
Offset := MaxOffset;
end;
scPosition, scTrack: begin
Offset := Trunc((ScrollPos
/ Scrollbar1.Max) * MaxOffset);
Exit;
end;
scTop: begin
Offset := 0;
Exit;
end;
scBottom: begin
Offset := MaxOffset;
Exit;
end;
scEndScroll: begin
18. março
2015
18
end;
end;
ScrollPos := Trunc((Offset /
ItemCount) * ScrollBar1.Max);
ListView1.Refresh;
end;
procedure TfrmMain.
ScrollBar1Change(Sender:
TObject);
begin
ListView1.Refresh;
end;
TFileSaveThread – Nossa thread de leitura
Nosso ambiente multithread é o que fará diferença neste processo de
leitura, somando ao fato do objeto de TListView estar em modo virtual. São
estas duas características que “aceleram” esta funcionalidade.
Nossa thread chamará o método FileReadMemory, que fará a realização
de leitura das linhas internamente para a nossa declarada estrutura TLine-
ReaderList. Segue o fonte abaixo de sua implementação, e onde está sendo
empregada:
TFileSaveThread = class(TThread)
protected
procedure Execute;
override;
public
Id: integer;
strSplittedText: string;
constructor
Create(CreateSuspended:
Boolean; const myID: integer;
const mySplittedText: string);
procedure FileReadMemory;
end;
constructor TFileSaveThread.
Create(CreateSuspended:
Boolean;
const myID: integer; const
mySplittedText: string);
begin
inherited
Create(CreateSuspended);
Self.Id := myID;
Self.strSplittedText :=
mySplittedText;
Priority := tpNormal;
end;
procedure TFileSaveThread.
Execute;
begin
FreeOnTerminate := True;
Synchronize(FileReadMemory);
end;
procedure TFileSaveThread.
FileReadMemory;
var
strList: TStringList;
i: integer;
list: TList;
obj: TMyObject;
begin
strList := TStringList.
Create;
list := ThreadList.
LockList;
try
strList.Text := (Self.
strSplittedText);
obj := TMyObject(list[0]);
for i := 0 to strList.Count
- 1 do
begin
frmMain.FLineReaderList.
Add(TLineReader.Create(strList.
Strings[i], obj.Counter));
inc(obj.Counter);
Inc(frmMain.lineCounter);
end;
frmMain.RefreshProgressBar;
finally
FreeAndNil(strList);
ThreadList.UnlockList;
end;
end;
StrmInput := TFileStream.
Create(StrFilename,fmOpenRead
or fmShareDenyNone);
try
Self.Disable;
try
while (StrmInput.Position
< StrmInput.Size) and (Tag = 0)
do
begin
SequentialFile := Chang
eFileExt((ExtractFilePath(StrFi
lename) +
19. março
2015
19
IncludeTrailingPathDe
limiter(tempFolder) + ExtractFi
leName(StrFilename)),’.’+Format
(‘%.03d’,[FileNumber]));
SequentialId :=
StrToIntDef(Self.ExtractFileExt
AfterDot(SequentialFile), 0);
//StrmOutput
:= TFileStream.
Create(SequentialFile
,fmCreate); ==> Don´t use: it´s
very slow !!
StrmOutput :=
TMemoryStream.Create;
try
if StrmInput.
Size - StrmInput.Position <
PartFileSize then
PartFileSize :=
StrmInput.Size - StrmInput.
Position;
StrmOutput.CopyFrom(S
trmInput,PartFileSize);
case fSelectedType of
StPartRead:
TFileReadThread.Create(False,
SequentialFile, SequentialId,
{PartFileSize,} Biblioteca.Memo
ryStreamToString(StrmOutput));
StMerge:
TFileSaveThread.Create(False,
SequentialId, Biblioteca.Memory
StreamToString(StrmOutput));
end;
Application.
ProcessMessages;
finally
FreeAndNil(StrmOutput);
end;
Inc(FileNumber);
end;
finally
FreeAndNil(StrmInput);
end;
Segunda parte de leitura de arquivos – o ClientDataSet de
apoio
Nesta segunda parte, haverá uma alteração em como será realizada a
leitura de arquivos. As partes divididas deste arquivo serão gravadas direta-
menteemumobjetodeTClientDataSet,aoinvésdesergravadanaquelanossa
estrutura de apoio TLineReaderList.
Pessoalmente, prefiro a primeira opção, a que foi explicada até agora. O
TListViewsecomportamaiseficientee“seguro”narenderizaçãodaslinhasde
texto do que um objeto de TClientDataSet realizaria. Muitos testes e esforços
para unir do “útil ao agradável” fazendo um merge de tudo para um TClien-
tDataSet falharam e me frustraram – não é tão eficiente quanto a primeira
alternativa–oTListViewvenceemdisparada.Entãopraqueabordareleagora?
Mais para uma questão didática – de como o processo pode ser salvo parte a
parte em um fluxo alternativo, onde clicando na parte desejada todo o conte-
údo da mesma é impresso na tela para o usuário. Em vez de ir renderizando
as linhas por meio de um objeto TScrollBox todo o conteúdo já é disponível
em um objeto TMemo – não é a mesma coisa. Mas funciona, desde que com
bom-senso (não foi testado à exaustão) e sinceramente, algumas vezes a me-
móriareclamaenviandoexceçõesaocompiladordeinsuficiênciadememória.
O leitor vai preferir a primeira opção, por raramente apresentará erros
de falta de memória.
ComoTListview,mesmocomestasrazõescitadasacimaaaplicaçãoainda
funciona,possivelmenteumpoucomaislento–algunssegundosamais–mas
travarjáseráalgomaisdifícildeacontecer.Omesmojánãoserápossíveldizer
comasegundaalternativa–oTClientDataSet–chamareleacadathreadnãofoi
umresultadotãosatisfatório–apromessadelertodasaspartesdeumarquivo
grandeemquestãopodefalhar.Assim,omaisseguroéaprimeiraalternativa.
Figuras 07/08/09 – Exibição do FastFile com a segunda opção escolhida – com o
objeto TClientDataSet em ação.
20. março
2015
20
Figuras10/11–ExibiçãodoFastFilecomasegundaopçãoescolhida–comoobjeto
TClientDataSet em ação – carregando o nosso arquivo texto de carga – o “loadfile05.
txt” com 1.2 GB de tamanho.
Comparação final: TListView x TClientDataSet
Fator TListView TClientDataSet
Agilidade Sim Sim
Carregamento do arquivo Sim Sim, mas pode falhar
Leitura das partes do arquivo Sim Sim, mas pode falhar
Re-leitura Sim Sim, mas pode falhar
Eficiência Sim Sim/Não
Confiabilidade Sim Sim/Não
Acesso direto às partes Não Sim
Editar manualmente as partes Não Sim
Leitura Virtual para Agilidade Sim Não
Portanto,melhoropçãoeleita:TListView!Éocomponentequelerátodos
os dados velozmente e quantas vezes forem necessárias, sem correr o risco
de perder os dados da leitura no meio do caminho. Lembrando que o compo-
nentedeveestaremmodovirtual,comapropriedadeOwnerDatacomoTrue.
Conclusão
Vimos duas alternativas interessantes para a leitura de arquivos grandes.
O propósito do aplicativo desenvolvido especialmente para esta edição (Fas-
tFile) é na verdade um mero leitor de arquivos, com sua ideia de dividi-lo em
partes e ler cada uma delas, pois quebrando o arquivo em partes e lendo é
mais fácil e mais rápido do que ler ele todo de uma vez, sem falar que lendo
todo ele de uma vez não vai funcionar se o arquivo é muito grande. Vai dar
erros de falta de memória, memória insuficiente, etc; e a leitura não vai ser
feita. Daí esta minha implementação que felizmente resolve para este tipo
de questão. Esperar alguns segundos para ler arquivos de mais de um 1 GB
não é um trabalho árduo de paciência pra ninguém – um objeto de progresso
(TProgressBar)notificaráoandamentodarotinapassoapassoparacertificarao
usuárioqueoFastFileestátrabalhando,comasthreadsdeleituraemsegundo
plano, para carregar o arquivo e disponibilizar ele nos objetos instanciados
(classe TListView/TClientDataSet) e assim poder lê-lo integralmente e sem
problema algum.
Oaplicativolerálinhaalinhadosarquivos(opção1)–maselenãoprocessa
elas – poderia ser implementado um evento de resposta a isso – recomendá-
vel para parametrizações com um banco de dados, por exemplo – algo como
“OnProcessLine(const iLine: index; const strFrase: string)”. O que discutimos
aqui é o mais complexo – é o processamento da leitura em si, linha a linha – e
não o que fazer com elas, além de exibi-las! Pois o fator tamanho é crucial
para o desempenho e a eficiência do nosso processo de leitura. Sem uma
alternativa viável como implementamos, não seria possível tradicionalmente
realizaresseprocessamentodispendiosodememóriapelosmétodospadrões.
Daí nossa construção do FastFile.
Portanto, conforme eu já disse ele é um mero leitor de arquivos, porque
oleitornãovaiesperaroutrasfuncionalidadescontidasnoFastFile–claroque
muitas coisas poderiam ser acrescentadas, mas isso já assunto para outros
artigos. Sugestões são sempre bem-vindas, o programa é freeware, portanto
sinta-seavontade,boadiversãocomosfontesinclusos,apenasumacitaçãode
copyright ao meu nome e tudo está resolvido. Bons estudos e até a próxima!
suporte@theclub.com.br
Hamden Vogel
Analista de Sistemas pós-graduado em Engenharia de Software pela
UPIS e Programador Delphi com larga experiência desde 2000, tem de-
senvolvido e vendido softwares em Delphi para a África e Estados Unidos,
além do mercado nacional. Colaborou com dicas e componentes para sites
especializadosemDelphi. Tambémdesenvolveemoutraslinguagenscomo
C/C++, ASP, PHP e .NET.
Sobre o autor
21. março
2015
21
Neste mês abordarei um assunto presente em todos os sistemas, o uso
de autenticação de usuários, ou seja, criarei uma tela de login para quem está
desenvolvendo para a plataforma Android. Com os recursos do Android em
suaversão4.4poderemosimplementartécnicasmuitolegaisparaestatarefa.
No primeiro momento será criada uma classe contendo dados do usuário,
comoporexemplo:“Usuário”e“Senha”.ATeladeLoginseráherdadadeuma
“Activity” e o lay-out será desenhado a partir de um arquivo “.xml”, ou seja,
não teremos nada de diferente.
Criando o Exemplo
O primeiro passo seria criar o projeto, para quem não sabe clique em
“File/New/AndroidApplicationProject”definindoumNomeparaaaplicação,
projeto e o pacote. No meu caso foi definido como:
Application Name: Login
Project Name: Login
Package Name: com.example.login
RecomendotambémfazerousodoSDK4.4-API19,oAndroid4.4KitKat.
Ver Imagem 01.
Figura 01: Criando uma aplicação Android.
Android – Criando uma
Tela de Login
Ospróximospassosdeveremosseguirasconfiguraçõespadrõesdeprojeto.
(Nãodetalhareiestaetapapoistemosinúmerosartigosemnossarevistasobre
esteassunto).ComoprojetocriadopodemosnotarapresençadeumaActivity
chamada “MainActivity.java” e de um arquivo de lay-out “activity_main.xml”,
ambos serão aproveitados para chamar a nossa tela de Login mais adiante.
Partiremos então para a criação da classe “Login”.
Classe “Login.java”
Clique com o botão direito sobre o diretório “src/com.example.login” e
escolha o item “New/Class”. Esta classe irá conter os atributos “Usuario” e
“Senha” com os respectivos “Gets” e “Sets” e o método “ValidarUsuario()”.
Teremos como referência o uso de duas constantes do tipo texto, sendo USU-
ARIO e SENHA. Farei o uso das mesmas para fins didáticos, mas ressalto que
poderíamos receber estes dados de outra origem, como por exemplo de um
banco de dados. Ver Listagem 01.
package com.example.login;
public class Login
{
private static final String
USUARIO = “THECLUB”;
private static final String
SENHA = “123456”;
Teremos as duas constantes do tipo texto contendo valores padrões.
private String Usuario;
private String Senha;
public String getUsuario()
{
return Usuario;
22. março
2015
22
}
public void setUsuario(String
usuario)
{
Usuario = usuario;
}
public String getSenha()
{
return Senha;
}
public void setSenha(String
senha)
{
Senha = senha;
}
Teremos também os atributos “Usuário” e “Senha” devidamente encap-
sulados.
public Login()
{
}
No método construtor não faremos nada de diferente.
public boolean
ValidarUsuario()
{
if (Usuario.equals(“”))
{
return false;
}
else if (Senha.equals(“”))
{
return false;
}
else if (!Usuario.
equals(USUARIO) || !Senha.
equals(SENHA))
{
return false;
}
else
{
return true;
}
}
No método “ValidarUsuario()” não teremos nenhum parâmetro de en-
trada e sim um de saída. Retornaremos um valor booleano realizando um
encadeamento de “ifs” testando se o atributo Usuário ou Senha estão vazios
e se os mesmos correspondem aos valores definidos nas constantes. Através
do resultado deste método validamos os dados digitados.
}
Listagem 01: Classe Login.
O nosso projeto de exemplo possuirá as seguintes atividades com seus
respectivos arquivos “XML”, podemos conferir detalhadamente abaixo:
1) MainActivity.java/activity_main.xml (Tela que conterá a chamada para
a tela de Login)
2) LoginAtividade.java/login.xml (Tela para efetuar o Login)
3) CadastroAtividade.java/cadastro.xml (Tela que se abrirá após a auten-
ticação do usuário)
Respeitandoaestruturadescritaacima,deveremoscriartodososarquivos
responsáveis pelo funcionamento do projeto, ver Figura 02.
Figura 02: Estrutura do projeto.
23. março
2015
23
Listagem 2
1) Main_activity.xml
Nesta tela teremos apenas um botão responsável por chamar a tela de
login.Atravésdeledisparamosométodo“OnActivityResult”queserádiscutido
logo em seguida. Ver Figura 03.
Figura 03: Tela para chamar o Login.
O XML correspondente, Ver Listagem 02.
<RelativeLayout
xmlns:android=”http://schemas.
android.com/apk/res/android”
xmlns:tools=”http://
schemas.android.com/tools”
android:layout_width=”match_
parent”
android:layout_
height=”match_parent”
android:paddingBottom=”@
dimen/activity_vertical_margin”
android:paddingLeft=”@
dimen/activity_horizontal_
margin”
android:paddingRight=”@
dimen/activity_horizontal_
margin”
android:paddingTop=”@dimen/
activity_vertical_margin”
tools:context=”.
MainActivity” >
<Button
android:id=”@+id/
btnLogin”
android:layout_
width=”wrap_content”
android:layout_
height=”wrap_content”
android:layout_
centerHorizontal=”true”
android:onClick=”Login”
android:text=”Efetuar
Login” />
</RelativeLayout>
Codificando a Atividade “main_activity.java”
Nesta atividade teremos que nos focar no método “Login” e no “OnActi-
vityResult”, sendo respectivamente para invocar a tela de login e para tratar
o retorno do mesmo.
Conferir Listagem 03.
package com.example.login;
import android.os.Bundle;
import android.app.Activity;
import android.content.Intent;
import android.view.Menu;
import android.view.View;
Importaremos algumas bibliotecas essenciais.
public class MainActivity
extends Activity {
@Override
protected void onCreate(Bundle
savedInstanceState)
{
super.
onCreate(savedInstanceState);
24. março
2015
24
Listagem 5
setContentView(R.layout.
activity_main);
}
Método que será disparado na
criação do lay-out.
public void Login(View view)
{
Intent login = new
Intent(MainActivity.this,
LoginAtividade.class);
startActivityForResult(login,
1);
}
Método que fará a chamada da Atividade “LoginAtividade”. Trataremos o
retorno da mesma através da função “StartActivityForResult”.
@Override
protected void
onActivityResult(int
requestCode, int resultCode,
Intent data)
{
if (resultCode == Activity.
RESULT_OK && requestCode == 1)
{
startActivity(new
Intent(MainActivity.this,
CadastroAtividade.class));
}
}
Já no método sobrescrito “OnActivityResult” comparamos o atributo
“resultCode” para nos certificarmos que o usuário clicou no botão “OK” e
o “requestCode” para o valor 1, indicando que a autenticação foi realizada
com sucesso.
}
Listagem 03.
2) login.xml
Deveremos inserir dois TextViews, dois Editexts e um Button, com as
informações referentes ao usuário. Ver Imagem 04.
Figura 04: Tela de Login.
O XML correspondente, conferir Listagem 05.
<?xml version=”1.0”
encoding=”utf-8”?>
<LinearLayout
xmlns:android=”http://schemas.
android.com/apk/res/android”
android:layout_width=”fill_
parent”
android:layout_height=”fill_
parent”
android:orientation=”vertic
al”
android:padding=”5dp” >
<TextView
android:id=”@+id/txtLogin”
android:layout_
width=”match_parent”
android:layout_
height=”wrap_content”
android:text=”Usuário”
android:textAppea
rance=”?android:attr/
textAppearanceMedium” />
<EditText
25. março
2015
25
android:id=”@+id/
edtUsuario”
android:layout_
width=”match_parent”
android:layout_
height=”wrap_content”
android:ems=”10” >
</EditText>
<TextView
android:id=”@+id/txtSenha”
android:layout_
width=”match_parent”
android:layout_
height=”wrap_content”
android:text=”Senha”
android:textAppea
rance=”?android:attr/
textAppearanceMedium” />
<EditText
android:id=”@+id/edtSenha”
android:layout_
width=”match_parent”
android:layout_height =
“wrap_content”
android:ems=”10”
android:inputType=”textPas
sword” />
<Button
android:id=”@+id/
btnEntrar”
android:layout_
width=”match_parent”
android:layout_
height=”wrap_content”
android:onClick=”Login”
android:text=”Entrar” />
</LinearLayout>
Codificando a Atividade “LoginAtividade.java”
Já na “LoginAtividade” iremos alimentar a classe “Login” criada anterior-
mente com os dados necessários. Ver Listagem 06.
package com.example.login;
import android.app.Activity;
import android.app.AlertDialog;
import android.os.Bundle;
import android.view.View;
import android.widget.EditText;
Faremos o uso de algumas bibliotecas.
public class LoginAtividade
extends Activity
{
private EditText edtUsuario;
private EditText edtSenha;
Deveremos declarar duas variáveis privadas, ambas para inicializar os
“EditTexts”.
@Override
protected void onCreate(Bundle
savedInstanceState)
{
super.
onCreate(savedInstanceState);
setContentView(R.layout.
login);
InicializaObjetos();
}
public void
InicializaObjetos()
{
edtUsuario = (EditText)
findViewById(R.id.edtUsuario);
edtSenha = (EditText)
findViewById(R.id.edtSenha);
}
O método “InicializaObjetos” irá realizar a referência dos objetos com
as variáveis criadas acima. Este método sempre será disparado no evento
“OnCreate”.
private void
MensagemInformativa(String
mensagen) {
new AlertDialog.
Builder(this)
.setTitle(“The Club”)
.setMessage(mensagen)
.setPositiveButton(“OK”,
null)
.setCancelable(false)
.show();
}
26. março
2015
26
Listagem 7
Ométodo“MensagemInformativa”recebecomoparâmetroumavariável
do tipo texto que nos dará uma mensagem informativa ao usuário de acordo
com a ocasião. Ele faz o uso da classe “AlertDialog” com alguns atributos
comoporexemplo:“setTitle”(Inserirtítulonacaixadediálogo),“SetMessage”
(Mensagemdisparada),“setPositiveButton”(BotãoOk)e“setCancelable”(in-
dicandoquenãopossuiobotãocancelar)eométodo“show”(paracarregá-lo).
public void Login(View v)
{
Login classe_login = new
Login();
classe_login.
setUsuario(edtUsuario.
getText().toString());
classe_login.
setSenha(edtSenha.getText().
toString());
if (classe_login.
ValidarUsuario() == false)
{
MensagemInformativa(“Dados
Incorretos, Favor preenchê-
los corretamente!”);
}
else
{
setResult(Activity.
RESULT_OK);
finish();
}
}
Ométodo“Login”recebecomoparâmetroaprópriaView,sendodisparado
noevento“OnClick”doBotão.Deveremosinstanciaraclasse“Login” setando
o usuário e a senha logo em seguida. Faremos um “If” com base no método
“classe_login.ValidarUsuario()” comparando se o retorno é verdadeiro ou
falso. Caso o retorno for “falso” disparamos uma mensagem para o usuário,
caso contrário liberaremos o acesso com o auxílio do método “setResult” e o
“finish()” para fechar a nossa Atividade.
}
Listagem 06.
3-) cadastro.xml
Esta tela seria apenas para informar ao usuário que o acesso foi liberado.
Fiquem a vontade para utilizar o que desejar. Ver Imagem 05.
Figura 05: Tela informativa de acesso liberado.
O código XML na Listagem 07.
<RelativeLayout
xmlns:android=”http://schemas.
android.com/apk/res/android”
xmlns:tools=”http://
schemas.android.com/tools”
android:layout_width=”match_
parent”
android:layout_
height=”match_parent”
android:paddingBottom=”@
dimen/activity_vertical_margin”
android:paddingLeft=”@
dimen/activity_horizontal_
margin”
android:paddingRight=”@
dimen/activity_horizontal_
margin”
android:paddingTop=”@dimen/
activity_vertical_margin”>
28. março
2015
28
DeveremosnosatentarparaoTrechodocódigoreferenteàTeladeLogindo
Sistema.Teremosquerealizaralgumasconfiguraçõesparaqueatelafiquecom
umlay-outagradávelparaousuário.Apropriedade“android:screenOrientation”
deixaremos como “portrait”. Já no “android:theme” deixaremos como “@
android:style/Theme.Dialog”.
Exemplo em “Run-Time”
O resultado final poderá ser conferido na Imagem 06.
Conclusões
Pudemos aprender neste artigo uma alternativa de como deveremos
proceder para criação de uma tela de Login. Procurei também ser bem claro
e objetivo dando a oportunidade de implementar novas funcionalidades caso
for necessário. Fiquem a vontade para baixar o arquivo de exemplo e testar
em suas aplicações.
Um abraço e até o mês que vem!
Figura 06: Executando o exemplo.
thiago@theclub.com.br
Thiago Cavalheiro Montebugnoli
adora aprender novas tecnologias. Formado pela Faculdade de Tecnologia de Botucatu
– SP (FATEC), já desenvolveu softwares utilizando a plataforma .NET, Delphi junto com Banco
de Dados SQL Server e Firebird. Atualmente trabalha no Centro de Processamento de Dados da
Prefeitura Municipal de Itaí-SP é colunista mensal da Revista The Club Megazine e é consultor
Técnico do The Club. Possui as seguintes certificações: MCP - Microsoft Certified Professional,
MCTS-MicrosoftCertifiedTechnologySpecialist,MCAD-MicrosoftCertifiedApplicationDeveloper
e MCSD - Microsoft Certified Solution Developer.
Sobre o autor
30. março
2015
dicas the club
30
Firebird e Firedac
Nesta dica vamos demonstrar como realizar uma simples conexão no
banco de dados Firebird através dos componentes do Firedac e seguindo uma
estrutura semelhante com o já conhecido DBExpress.
Para iniciarmos adicione os seguintes componentes:
• FDConnection – Indicamos a conexão com nossa base de dados
assim como é feito no ‘SQLConnection’, veja exemplo abaixo:
• FDCommand – Neste componente indicamos a consulta SQL
que vamos utilizar, assim como realizado no ‘SQLDataSet’, este componente
se conecta automaticamente ao ‘FDConnection’ de sua aplicação mas, pode
alterar manualmente na propriedade ‘Connection’.
• FDTableAdapter – Assim como o ‘DataSetProvider’ este compo-
nente será responsável por realizar a conexão entre o banco de dados e a
aplicaçãoexecutandooscomandossolicitados.Conecteseu‘FDTableAdapter’
ao ‘FDCommand’ através da propriedade ‘SelectCommand’.
• FDMemTable – Por fim temos o componente ‘FDMemTabel’ que
será o nosso ‘ClientDataSet’, nele temos praticamente todas as funcionalida-
des que já conhecemos de seu predecessor, Conecte seu ‘FDMemTable’ ao
‘FDTableAdapter’ através da propriedade ‘Adapter’.
• FDPhysFBDriverLink –Estecomponenteéresponsávelporconectar
sua aplicação ao driver referente ao banco de dados que utiliza, ou seja, esse
componente muda de banco para banco. Veja abaixo outros exemplos:
FDPhysOracleDriverLink - ;
FDPhysMySQLDriverLink - .
• FDGUIxWaitCursor – Este componente é utilizado no Firedac para
exibir um cursor de espera nas conexões.
Após realizar todas as configurações insira os seguintes componentes:
• DBGrid, DBNavigator, DataSource.
Vamos utiliza-los apenas para exibir os dados, veja imagem abaixo: