<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>TechTips &#187; Delphi</title>
	<atom:link href="http://www.techtips.com.br/category/programacao/delphi/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.techtips.com.br</link>
	<description>Dicas de Tecnologia</description>
	<lastBuildDate>Wed, 24 Jun 2009 19:06:32 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0</generator>
		<item>
		<title>Criando e usando Listas encadeadas</title>
		<link>http://www.techtips.com.br/programacao/delphi/criando-e-usando-listas-encadeadas/</link>
		<comments>http://www.techtips.com.br/programacao/delphi/criando-e-usando-listas-encadeadas/#comments</comments>
		<pubDate>Wed, 24 Jun 2009 15:09:33 +0000</pubDate>
		<dc:creator>Gilberto Saraiva [MP]</dc:creator>
				<category><![CDATA[Delphi]]></category>
		<category><![CDATA[Linguagem Delphi]]></category>

		<guid isPermaLink="false">http://www.techtips.com.br/?p=231</guid>
		<description><![CDATA[Introdução: Pois bem, primeiro artigo aqui pro TechTips, serei breve(o quando for possível) e objetivo sobre o assunto em questão, e as dúvidas que surgirem envie-as na parte de comentários, okas? Antes de começar, uma pequena explicação sobre as nomeclaturas: &#8211; Lista encadeada(Chained List) ou Lista ligada(Linked list) são a mesma coisa, em algums cursos [...]]]></description>
			<content:encoded><![CDATA[<h3>Introdução:</h3>
<p>Pois bem, primeiro artigo aqui pro TechTips, serei breve(o quando for possível) e objetivo sobre o assunto em questão, e as dúvidas que surgirem envie-as na parte de comentários, okas?</p>
<p>Antes de começar, uma pequena explicação sobre as nomeclaturas: &#8211; Lista encadeada(Chained List) ou Lista ligada(Linked list) são a mesma coisa, em algums cursos um termo ou outro é usado mas o objetivo e estrutura não diferem.</p>
<p>Esse artigo está sendo escrito levando como base o desenvolvimento em Delphi 7, versões superiores a essa podem ter implementações nativas dessa estrutura ou mesmo disponibilizar facilitadores que fazem o código ser diferente.</p>
<h3>Lista encadeada:</h3>
<p>Algumas vezes quando precisamos guardar algumas informações picadas, como pacotes de dados de sockets ou audio, criamos uma lista encadeada que controla toda a informação sequencialmente e prove uma navegação nos dados guardados somente caminhando para frente ou para traz.</p>
<p><span id="more-231"></span>A estrutura de uma lista encadeada se divide em 2ª principais variáveis: Data(dados) e Next(ou Prior &#8211; Próximo ou Anterior &#8211; quando necessário), para cada item no seu encadeamento possue um dado(Ponteiro, valor ou alguma coisa que precisa guardar) e a referência para o próximo item ou anterior na lista. Lista encadeada não disponibiliza acesso direto os items, então você não poderá acessar um item sem navegar nos outros. Uma lista encadeada pode ser aperfeiçoada mas o principal objetivo é disponibilizar uma lista de capacidade quase infinita com a melhor performance do que outras técnicas.</p>
<p>Como você sabe, lista encadeadas não guardam indices para os itens(não tem acesso direto) e isso evita processos de reindexação(reorganização de indices) que consomem um grande tempo quando se tem uma lista grande de itens. Quando precisa-se remover um item de uma lista encadeada, você precisa de fazer a primeira melhoria na estrutura de encadeamento para segurar o item anterior e o próximo para cada item que tenha, e isso prove para você um caminho confortável para manipular os itens sem ter que escrever um monte de códigos e variáveis.</p>
<p>Escrevi a implementação abaixo para servir de base para criação de listas encadeadas com navegação frente-traz:</p>
<pre style="overflow: auto; height: 400px;">uses SysUtils;

type
  PPointer = ^Pointer;

  TChainedList = class
  private
    FFirst   : Pointer;
    FLast    : Pointer;
    FCurrent : Pointer;
    FCount   : Integer;
    function GetCurrent: PPointer;
  public
    constructor Create;
    destructor Destroy; override;

    function First : TChainedList;
    function Last  : TChainedList;
    function Prior : TChainedList;
    function Next  : TChainedList;

    function Add: TChainedList;
    function Remove: TChainedList; overload;
    function Remove(AChainedReleaser: Pointer): TChainedList; overload;

    property Current: PPointer read GetCurrent;
    property Count: Integer read FCount;
  end;

implementation

type
  PChainedItem = ^TChainedItem;
  TChainedItem = record
    Prior, Next: PChainedItem;
    Data: Pointer;
  end;

{ TChainedList }

constructor TChainedList.Create;
begin
  FCount := 0;
  FFirst := nil;
  FLast := nil;
  FCurrent := nil;
end;

destructor TChainedList.Destroy;
begin
  First;
  while Current &lt;&gt; nil do
    Remove;

  inherited;
end;

function TChainedList.GetCurrent: PPointer;
begin
  if FCurrent &lt;&gt; nil then
    Result := @PChainedItem(FCurrent).Data
  else
    Result := nil;
end;

function TChainedList.First: TChainedList;
begin
  FCurrent := FFirst;
  Result := Self;
end;

function TChainedList.Last: TChainedList;
begin
  FCurrent := FLast;
  Result := Self;
end;

function TChainedList.Prior: TChainedList;
begin
  if FCurrent &lt;&gt; nil then
    FCurrent := PChainedItem(FCurrent)^.Prior
  else
    FCurrent := nil;
  Result := Self;
end;

function TChainedList.Next: TChainedList;
begin
  if FCurrent &lt;&gt; nil then
    FCurrent := PChainedItem(FCurrent)^.Next
  else
    FCurrent := nil;
  Result := Self;
end;

function TChainedList.Add: TChainedList;
var
  pNew: PChainedItem;
begin
  New(pNew);
  pNew^.Prior := nil;
  pNew^.Next := nil;
  pNew^.Data := nil;

  if FFirst = nil then
  begin
    FFirst := pNew;
    FLast := pNew;
  end else
  begin
    pNew^.Prior := PChainedItem(FLast);
    PChainedItem(FLast)^.Next := pNew;
    FLast := pNew;
  end;

  FCurrent := FLast;
  Result := Self;
  Inc(FCount);
end;

function TChainedList.Remove: TChainedList;
var
  pCur: PChainedItem;
begin
  pCur := FCurrent;
  if pCur^.Data &lt;&gt; nil then
    raise Exception.Create('Current item memory leak detected.');

  if pCur^.Next &lt;&gt; nil then
    pCur^.Next^.Prior := pCur^.Prior;

  if pCur^.Prior &lt;&gt; nil then
    pCur^.Prior^.Next := pCur^.Next;

  if pCur = FFirst then
  begin
    FFirst := pCur^.Next;
    FCurrent := FFirst;
  end else if pCur = FLast then
  begin
    FLast := pCur^.Prior;
    FCurrent := FLast;
  end else
    FCurrent := pCur^.Next;

  Result := Self;
  Dispose(pCur);
  Dec(FCount);
end;

function TChainedList.Remove(AChainedReleaser: Pointer): TChainedList;
type
  TRelease = procedure(APointer: Pointer);
var
  PdrRelease: TRelease;
begin
  @PdrRelease := AChainedReleaser;
  PdrRelease(PChainedItem(FCurrent)^.Data);
  PChainedItem(FCurrent)^.Data := nil;
  Remove;
end;</pre>
<h3>O entendimento e utilização:</h3>
<p>Fiz utilização de <strong>^</strong>(circunflexo)s para evidenciar que o acesso é atravez de ponteiro(No caso desse código desde o Delphi 5 a optimização de código já consegue compilar corretamente sem necessidade de uso do ^).</p>
<p>Como vocês podem observar, a classe TChainedList é bastante robusta e prove um controle bem extenso sobre a lista criada, suas caracteristicas são:</p>
<ol>
<li>Navegação Frente-Traz, Inicio e Fim</li>
<li>Acesso ao dados guardados no item atraves da propriedade <strong>Current</strong></li>
<li>Controle de quantidade de items na lista</li>
<li>Métodos de adicão e remoção de items, sendo que a remoção disponibiliza um callback para liberação de memória dos dados guardados</li>
</ol>
<p>Sendo assim, o que é possível fazer com a utilização da TChainedList?<br />
- Vamos ao exemplo prático da utilização, veja abaixo:</p>
<dd>
<li><strong>O exemplo:</strong> Criar uma aplicação Win32 que o usuário escreva em um campo uma palavra e ao pressionar o botão &#8220;Adicionar&#8221; a palavra é adiciona à frase que eles está construindo e exibida em um local específico. Disponibilizar um botão &#8220;Limpar&#8221; para limpar a frase.</li>
</dd>
<p>Passos para iniciar a utilização de teste:</p>
<ol>
<li>Iniciar um projeto <strong>Win32</strong> no Delphi</li>
<li>nomear o Form principal para <strong>frmMain</strong></li>
<li>Adicionar um <strong>TEdit: edtWord</strong></li>
<li>Adicionar um <strong>TButton: btnAdd</strong> &#8211; Caption = &#8220;Adicionar&#8221;</li>
<li>Adicionar um <strong>TLabel: lblPhrase</strong></li>
<li>Adicionar um <strong>TButton: btnClean</strong> &#8211; Caption = &#8220;Limpar&#8221;</li>
<li>Criar uma variável tipo <strong>TChainedList</strong> de escopo publico em <strong>frmMain</strong> de nome <strong>Phrase</strong></li>
<li>Criar um método chamado <strong>UpdateList</strong> de escopo publico em <strong>frmMain</strong></li>
</ol>
<p>Código:</p>
<pre>uses ChainedListCtrl;

type
  TfrmMain = class(TForm)
    edtWord: TEdit;
    btnAdd: TButton;
    lblPhrase: TLabel;
    btnClean: TButton;
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure btnAddClick(Sender: TObject);
    procedure btnCleanClick(Sender: TObject);
  private
    { Private declarations }
  public
    Phrase: TChainedList;
    procedure UpdateList;
  end;

var
  frmMain: TfrmMain;

implementation

{$R *.dfm}</pre>
<p><em>Linkando</em> o evento FormCreate do <strong>frmMain</strong> o <strong>Phrase</strong> deve ser criado:</p>
<pre>{ Note: Create the Chain List Control Object
}
procedure TfrmMain.FormCreate(Sender: TObject);
begin
  Phrase := TChainedList.Create;
end;</pre>
<p><em>Linkando</em> o evento FormDestroydo <strong>frmMain</strong> o <strong>Phrase</strong> deve ser destruído:<br />
<span style="color: #ff0000;"><em>OBS: A destruição do objeto Pharse não está associada a liberação de memória dos items, então caso a o aplicativo seja fechado e o Pharse destruido sem limpar a lista ocorrerá vazamento de memória(vide btnCleanClick para liberação dos items)</em></span></p>
<pre>{ Note: Destroy the Chain Object
}
procedure TfrmMain.FormDestroy(Sender: TObject);
begin
  Phrase.Free;
end;</pre>
<p>Codificando o método <strong>UpdateList</strong>. Esse método é o responsável por exibir a frase, listando as palavras adicionadas na lista.</p>
<pre>{ Note: Update the Label to hold all the words
        included on the Chained list
}
procedure TfrmMain.UpdateList;
var
  sPhrase: string;
begin
  sPhrase := '';
  Phrase.First;
  while Phrase.Current &lt;&gt; nil do
  begin
    if sPhrase &lt;&gt; '' then
      sPhrase := sPhrase + ' ';

    sPhrase := sPhrase + PChar(Phrase.Current^);
    Phrase.Next;
  end;
  lblPhrase.Caption := sPhrase;
end;</pre>
<p><em>Linkando</em> o evento OnClick do <strong>btnAdd</strong> o texto escrito em <strong>edtWord</strong> deve ser adicionado a lista <strong>Phrase</strong>:</p>
<pre>{ Note: Add the text on the Chain
   p.s: StrNew create a copy of the string that will be managed
        out of the garbage collector(str refcount structure)
}
procedure TfrmMain.btnAddClick(Sender: TObject);
begin
  Phrase.Add.Current^ := StrNew(PChar(edtWord.Text));
  UpdateList;
end;</pre>
<p><em>Linkando</em> o evento OnClick do <strong>btnClean</strong> a lista <strong>Phrase</strong> deve ser limpa e os items devem ser removidos para evitar vazamento memória.</p>
<pre>{ Note: Clean the Chain list
   p.s: StrDispose release the memory of the create string
        to avoid memory leaks
}
procedure TfrmMain.btnCleanClick(Sender: TObject);
begin
  Phrase.Last;
  while Phrase.Current &lt;&gt; nil do
    Phrase.Remove(@StrDispose);
  UpdateList;
end;</pre>
<p>Os comentários em inglês no código estão presentes porque o artigo é uma transcrição do artigo <a href="http://gsaraiva.projects.pro.br/?p=418">Delphi: Chained List</a> juntamente com a publicação do <a href="http://gsaraiva.projects.pro.br/?p=417">Delphi: Utils :: TChainedList</a>.</p>
<h3>Entendendo a estrutura de uma Lista encadeada:</h3>
<p><em>Estou complementando aqui o artigo, o que vai diferir do artigo em inglês será essa parte, pois agora explicarei a estrutura da lista encadeada de forma mais programática.</em></p>
<p>De acordo com os exemplos e explicações acima podemos concluir que a lista é criada através dos itens existentes e relacionados e não por um outro objeto que controla os items individualmente, ou seja, um item sabe que o(s) &#8220;vizinho(s)&#8221; existe(m) sem precisar sair do seu escopo.</p>
<p>O funcionamento disso em programação é a base de referências(ponteiro), pois assim a movimentação de memória e consumo da mesma fica estrito a modificações nos itens e não na gerência da lista. Mas o que isso quer dizer?<br />
- Quer dizer que para se remover um item você precisa apenas avisar seu(s) vizinho(s) que ele não está mais na lista. Programaticamente falando o resultado disso é:</p>
<pre>Lista:
    Item1
      Next -&gt; Item2
                Next -&gt; Item3
                          Next -&gt; nil

Remoção do Item2
    Item1
      Next -&gt; Item2.Next -&gt; Item3
                              Next -&gt; nil

              Item2(Removido)
                Next -&gt; Item3</pre>
<p>O que foi feito acima foi somente a assimilação do Next do Item1 com o Next do Item2, resultando em uma lista que caminha do Item1 para o Item3, sendo que o Item2 ficará fora da sequência.</p>
<p>Outro fato importante é que trabalhando com referências, você não terá objetos repetidos, ou seja, se você modificar o Item3 seja pelo Item2.Next ou seja depois da remoção pelo Item1.Next você estará acessando o mesmo ponto da memória. Mas essas explicações não serão contempladas nesse artigo para não estender muito o assunto e perder o foco. Mas vale a dica de entendimento de referências(Pointeiros) para todos que não compreendem bem o estrutura da memória.</p>
<h3>Exemplo com descendência (mais código, menos dificuldade):</h3>
<p>Para simplificar um pouco as coisas, deixar a utilização dos ponteiros centralizada, você pode estender a classe da forma que precisar em seu projeto, neste caso vou exemplificar como seria a extensão de TChainedList para o nosso exemplo:</p>
<pre>type
  TPhraseChainedList = class(TChainedList)
  public
    procedure AddWord(const AWord: string);
    procedure RemoveWord;
    procedure Clear;
    function CurrWord: string;
  end;

{ TPhraseChainedList }

procedure TPhraseChainedList.AddWord(const AWord: string);
begin
  Add.Current^ := StrNew(PChar(AWord));
end;

procedure TPhraseChainedList.RemoveWord;
begin
  Remove(@StrDispose);
end;

procedure TPhraseChainedList.Clear;
begin
  Last;
  while Current &lt;&gt; nil do
    RemoveWord;
end;

function TPhraseChainedList.CurrWord: string;
begin
  Result := PChar(Current^);
end;</pre>
<p>Assim, na hora de utilizar, 4 métodos do nosso exemplo anterior vão ser modificados: FormCreate, UpdateList, btnAddClick e btnCleanClick;</p>
<pre>{ Note: Create the Chain List Control Object
}
procedure TfrmMain.FormCreate(Sender: TObject);
begin
  Phrase := TPhraseChainedList.Create;
end;

{ Note: Update the Label to hold all the words
        included on the Chained list
}
procedure TfrmMain.UpdateList;
var
  sPhrase: string;
begin
  sPhrase := '';
  Phrase.First;
  while Phrase.Current &lt;&gt; nil do
  begin
    if sPhrase &lt;&gt; '' then
      sPhrase := sPhrase + ' ';

    sPhrase := sPhrase + Phrase.CurrWord;
    Phrase.Next;
  end;
  lblPhrase.Caption := sPhrase;
end;

{ Note: Add the text on the Chain
}
procedure TfrmMain.btnAddClick(Sender: TObject);
begin
  Phrase.AddWord(edtWord.Text);
  UpdateList;
end;

{ Note: Clean the Chain list
}
procedure TfrmMain.btnCleanClick(Sender: TObject);
begin
  Phrase.Clear;
  UpdateList;
end;</pre>
<p>Caso seja interessante podemos estender ainda mais, criando uma função que me retorna a frase, assim não teriamos que nos preocupar com a geração da frase quando for preciso pegar o valor em outro local.</p>
<pre>  TPhraseChainedList = class(TChainedList)
  public
    ...
    function ThePhrase: string;
  end;

function TPhraseChainedList.ThePhrase: string;
begin
  Result := '';
  First;
  while Current &lt;&gt; nil do
  begin
    if Result &lt;&gt; '' then
      Result := Result + ' ';

    Result := Result + CurrWord;
    Next;
  end;
end;</pre>
<p>O UpdateList ficaria assim, ou mesmo deixaria de existir porque não teria uma grande utilidade após a implementação acima:</p>
<pre>{ Note: Update the Label to hold all the words
        included on the Chained list
}
procedure TForm1.UpdateList;
begin
  lblPhrase.Caption := Phrase.ThePhrase;
end;</pre>
<h3>Agradecimentos:</h3>
<p>Quero aqui agradecer ao pessoal de bem que sempre está em contato comigo me dando apoio.<br />
Ao Leonel que deixou eu escrever esse monte de coisas aqui.<br />
Ao Itamar Bermond que fornece a hospedagem do meu site, porque sem isso talvez nem escreveria nada de útil na internet.<br />
À meus punhos e cérebro.</p>
<p>E lembrando: <em>Fé move montanhas e a programação move o futuro.</em></p>
<p>Abraços e agradeço a paciência.</p>
<p><center>&copy; <a href="http://gsaraiva.projects.pro.br/">TechTips</a></center></p>]]></content:encoded>
			<wfw:commentRss>http://www.techtips.com.br/programacao/delphi/criando-e-usando-listas-encadeadas/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Movendo colunas e linhas em um StringGrid.</title>
		<link>http://www.techtips.com.br/programacao/movendo-colunas-e-linhas-em-um-stringgrid/</link>
		<comments>http://www.techtips.com.br/programacao/movendo-colunas-e-linhas-em-um-stringgrid/#comments</comments>
		<pubDate>Fri, 27 Mar 2009 14:58:33 +0000</pubDate>
		<dc:creator>acidbytes</dc:creator>
				<category><![CDATA[Delphi]]></category>
		<category><![CDATA[Programação]]></category>
		<category><![CDATA[VCL/RTL]]></category>

		<guid isPermaLink="false">http://www.techtips.com.br/programacao/movendo-colunas-e-linhas-em-um-stringgrid/</guid>
		<description><![CDATA[&#160; &#160;&#160;&#160;&#160;&#160; Na maioria dos componentes Grids, de terceiros, você pode observar que o usuário pode mover colunas e linhas usando o mouse. Aliás, o usuário espera este comportamento de um Grid. Então, como fazer isso usando um TStringGrid? &#160;&#160;&#160;&#160;&#160; Como sempre, se é isso que você estava querendo implantar em seu aplicativo, mais uma [...]]]></description>
			<content:encoded><![CDATA[<p>&#160;</p>
<p align="justify">&#160;&#160;&#160;&#160;&#160; Na maioria dos componentes Grids, de terceiros, você pode observar que o usuário pode mover colunas e linhas usando o mouse. Aliás, o usuário <strong><font color="#ff0000"><em>espera</em></font></strong> este comportamento de um Grid. Então, como fazer isso usando um TStringGrid? </p>
<p align="justify">&#160;&#160;&#160;&#160;&#160; Como sempre, se é isso que você estava querendo implantar em seu aplicativo, mais uma vez “seus pobrêma se acabaram-se”,&#160; apresentamos o incrível <strong><font color="#008000"><em>GridColumnRowMoveitor</em></font></strong> Tabajara.</p>
<p>&#160;&#160;&#160;&#160;&#160; Mais uma vez… mão na massa e chega de enrolação.</p>
<p align="justify">&#160;&#160;&#160;&#160;&#160; Primeiro de tudo, se você der uma olhada mais aprofundada no componente <strong>TCustomGrid</strong> você verá que os métodos <strong>MoveColumn</strong> e <strong>MoveRow</strong> estão lá, fazem parte do componente, mas eles estão ocultos no TStringGrid, eles são herdados do ancestral TCustomGrid porém não estão acessíveis no descendente, o motivo?? Ora, vai lá saber o que se passa na cabeça dos garotos da Codegear…</p>
<p align="justify">&#160;&#160;&#160;&#160;&#160; Como resolver esse problema? Simples e fácil, sem maiores complicações, basta fazer uma herança de TStringGrid e redeclarar estes métodos como public.</p>
<p><strong>type      <br /></strong>&#160;&#160;&#160; TNovoGrid <font color="#0000ff">=</font> class(TStringGrid)     <br />&#160;&#160;&#160; <strong>public</strong>     <br />&#160;&#160;&#160; procedure MoveColumn(FromIndex, ToIndex: LongInt)<font color="#0000ff"><strong>;</strong></font>     <br />&#160;&#160;&#160; procedure MoveRow(FromIndex, ToIndex: LongInt)<strong><font color="#0000ff">;</font></strong>     <br />&#160;&#160; <strong>end<font color="#0000ff">;</font></strong></p>
<p>&#160;&#160; Para implementar estes métodos é muito simples, basta na implementação, chamar o ancestral e passar para ele o comando:</p>
<p><strong>procedure</strong> TNovoGrid.MoveColumn(FromIndex, ToIndex: LongInt)<font color="#0000ff"><strong>;</strong></font>     <br /><strong>begin</strong>     <br />&#160;&#160;&#160; inherited<font color="#0000ff"><strong>;</strong></font>     <br /><strong>end<font color="#0000ff">;</font></strong></p>
<p><strong>procedure </strong>TNovoGrid.MoveRow(FromIndex, ToIndex: LongInt)<strong><font color="#0000ff">;</font></strong>     <br /><strong>begin</strong>     <br />&#160;&#160;&#160; inherited<font color="#0000ff">;</font>     <br /><strong>end<font color="#0000ff">;</font></strong></p>
<p align="justify">&#160;&#160;&#160;&#160; Você não precisa registrar este componente na paleta de componentes. Use o TStringGrid ou qualquer descendente de TCustomGrid normalmente como já faz hoje, e quando você precisar usar estes métodos, simplesmente faça um typecast (conversão de tipos) para a nova classe, e pronto. Veja o exemplo abaixo:</p>
<p><strong>procedure </strong>TForm1.Button1Click(Sender: TObject);     <br /><strong>begin      <br /></strong>&#160;&#160;&#160;&#160;&#160;&#160; TNovoGrid(StringGrid1).MoveColumn(<font color="#800000"><strong>2</strong></font>, <font color="#800000"><strong>5</strong></font>)<font color="#0000ff">;</font>     <br /><strong>end</strong><font color="#0000ff">;</font></p>
<p><font color="#0000ff">&#160;&#160;&#160; </font><font color="#000000">Bom, é isso aí, até a próxima.      <br />&#160;&#160;&#160; <a href="http://www.spectrus.com.br">www.spectrus.com.br</a></font></p>
<p><center>&copy; <a href="http://www.spectrus.com.br">TechTips</a></center></p>]]></content:encoded>
			<wfw:commentRss>http://www.techtips.com.br/programacao/movendo-colunas-e-linhas-em-um-stringgrid/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Mapas do Google no seu aplicativo Delphi.</title>
		<link>http://www.techtips.com.br/programacao/mapas-do-google-no-seu-aplicativo-delphi/</link>
		<comments>http://www.techtips.com.br/programacao/mapas-do-google-no-seu-aplicativo-delphi/#comments</comments>
		<pubDate>Wed, 25 Mar 2009 18:44:51 +0000</pubDate>
		<dc:creator>acidbytes</dc:creator>
				<category><![CDATA[Delphi]]></category>
		<category><![CDATA[Programação]]></category>

		<guid isPermaLink="false">http://www.techtips.com.br/programacao/mapas-do-google-no-seu-aplicativo-delphi/</guid>
		<description><![CDATA[&#160; &#160;&#160;&#160;&#160;&#160; Bom, você certamente já pesquisou algum endereço pelo google maps, e ficou imaginando que colocar aquilo no seu aplicativo seria uma boa idéia. &#160;&#160;&#160;&#160;&#160; Pois agora, seus problemas “acabaram-se”, com o novo googlemapeitorparaseuaplicativeitor Tabajara, as coisas finalmente vão acontecer. &#160;&#160;&#160;&#160;&#160; Veja abaixo como fazer para colocar o Google para trabalhar para você, e [...]]]></description>
			<content:encoded><![CDATA[<p>&#160;</p>
<p>&#160;&#160;&#160;&#160;&#160; Bom, você certamente já pesquisou algum endereço pelo google maps, e ficou imaginando que colocar aquilo no seu aplicativo seria uma boa idéia.    <br />&#160;&#160;&#160;&#160;&#160; Pois agora, seus problemas “acabaram-se”, com o novo googlemapeitorparaseuaplicativeitor Tabajara, as coisas finalmente vão acontecer.</p>
<p>&#160;&#160;&#160;&#160;&#160; Veja abaixo como fazer para colocar o Google para trabalhar para você, e mostrar para seus clientes, ou para o chefe, como você é esperto (Não tanto quanto o Larry Page e o Sergey Brin, pois eles ganham fortunas com o Google, e você ainda está bem distante de conseguir comprar 1 Boeing só para fazer baladas nos céus como eles fazem).</p>
<p>&#160;&#160;&#160;&#160; Mãos à obra entonces:</p>
<p>&#160;&#160;&#160;&#160; Temos uma tabela de Clientes, 4 campos desta tabela nos interessam, que contém os dados que usaremos para pesquisar no mapa.</p>
<p>&#160;&#160;&#160; <strong><font color="#800000">Logradouro</font></strong> = Contém o nome do logradouro do endereço, por exemplo “<strong>Rua Jesuíno Arruda</strong>”.     <br />&#160;&#160;&#160; <strong><font color="#800000">Numero</font></strong> = Contém o número do endereço, apenas o número e não o complemento (sala, loja, etc), por exemplo: <strong>769</strong>&#160; <br />&#160;&#160;&#160; <strong><font color="#800000">Cidade</font></strong> = O nome da cidade, por exemplo: <strong>São Paulo</strong>     <br />&#160;&#160;&#160; <strong><font color="#800000">UF</font></strong> = A sigla do estado, exemplo <strong>SP.</strong></p>
<p>Vamos criar uma função que vai fazer o trabalho, é simples, prático e bem rápido.</p>
<p><font face="Arial"><strong>procedure</strong> TForm1.CarregaMapa;       <br /><strong>begin</strong>       <br />&#160; ShellExecute(0, Nil,       <br />&#160;&#160;&#160; PChar(&#8216;http://maps.google.com.br/maps?f=q&amp;source=s_q&amp;hl=pt-BR&amp;geocode=&amp;q=&#8217; +Clientes.FieldByName(&#8216;Logradouro&#8217;).AsString + &#8216;, &#8216; + Clientes.FieldByName(&#8216;Numero&#8217;).AsString + &#8216;, &#8216; +       <br />&#160;&#160;&#160;&#160;&#160; Clientes.FieldByName(&#8216;Cidade&#8217;).AsString + &#8216;-&#8217; + Clientes.FieldByName(&#8216;UF&#8217;).AsString + &#8216;&amp;jsv=143c&amp;sll=-23.186453,-46.884453&#8242; +       <br />&#160;&#160;&#160;&#160;&#160; &#8216;&amp;sspn=0.478436,0.545883&amp;g=&amp;ie=UTF8&amp;ct=clnk&amp;cd=1&#8242;), <strong>Nil</strong>, <strong>Nil</strong>, 0);       <br /><strong>end</strong>;</font></p>
<p>&#160;&#160;&#160; Basta chamar a função e será carregado o browser com o mapa correspondente ao endereço passado.</p>
<p>&#160;&#160;&#160; No próximo post vamos ver como fazer para, além de mostrar o mapa, traçar a rota entre dois endereços.</p>
<p>&#160;&#160;&#160; Como sempre falo : <strong><em><font color="#ff0000">Google é seu amigo, use-o</font></em></strong>.     <br />&#160;&#160;&#160; <a href="http://www.spectrus.com.br">www.spectrus.com.br</a></p>
<p><center>&copy; <a href="http://www.spectrus.com.br">TechTips</a></center></p>]]></content:encoded>
			<wfw:commentRss>http://www.techtips.com.br/programacao/mapas-do-google-no-seu-aplicativo-delphi/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>Modulariza&#231;&#227;o de Aplicativos &#8211; Single Package</title>
		<link>http://www.techtips.com.br/programacao/modularizao-de-aplicativos-single-package/</link>
		<comments>http://www.techtips.com.br/programacao/modularizao-de-aplicativos-single-package/#comments</comments>
		<pubDate>Tue, 04 Nov 2008 18:42:50 +0000</pubDate>
		<dc:creator>Wanderson</dc:creator>
				<category><![CDATA[Delphi]]></category>
		<category><![CDATA[Programação]]></category>
		<category><![CDATA[Práticas]]></category>

		<guid isPermaLink="false">http://www.techtips.com.br/programacao/modularizao-de-aplicativos-single-package/</guid>
		<description><![CDATA[Quem desenvolve aplicativos modularizados, pode já ter se deparado com uma desvantagem comum quando se trata de distribuir pacotes de runtime: como controlar quais packages distribuir junto com o aplicativo/módulos e suas versões e facilitar suas atualizações? Normalmente quando compilamos um aplicativo com a opção “Build with runtime packages” marcada, no mínimo teremos que redistribuir [...]]]></description>
			<content:encoded><![CDATA[<p>Quem desenvolve aplicativos modularizados, pode já ter se deparado com uma desvantagem comum quando se trata de distribuir pacotes de runtime: como controlar quais packages distribuir junto com o aplicativo/módulos e suas versões e facilitar suas atualizações?</p>
<p>Normalmente quando compilamos um aplicativo com a opção “Build with runtime packages” marcada, no mínimo teremos que redistribuir os pacotes rtlxx.bpl e vclxx.bpl (onde o “xx” equivale à versão do Delphi, pelo menos até o Delphi 7), mais os pacotes referenciados pelas units da vcl e/ou de terceiros.</p>
<p>Agora imagine um projeto grande, onde temos vários componentes de terceiros empregados. Quantos arquivos extras se tornariam dependências para o aplicativo?</p>
<p>Procurando uma maneira simples para minimizar o número de arquivos a serem distribuídos em conjunto com um aplicativo que use runtime packages, me deparo com o excelente tutorial de <a href="http://www.saxon.co.uk/SinglePkg/">Keith Johnson</a>, ao qual não posso acrescentar muita coisa, por já ser muito completo e didático. Contento-me a simplificá-lo e torná-lo útil para a realidade de muitos aqui.</p>
<h3>Direto ao ponto</h3>
<p><a href="http://www.techtips.com.br/wp-content/uploads/2008/11/clip-image001.gif"><img style="0px" src="http://www.techtips.com.br/wp-content/uploads/2008/11/clip-image001-thumb.gif" border="0" alt="clip_image001" width="379" height="180" /></a></p>
<p>Figura 1 – Aplicativo com pacotes dinâmicos de forma convencional.</p>
<p><a href="http://www.techtips.com.br/wp-content/uploads/2008/11/clip-image002.gif"><img style="0px" src="http://www.techtips.com.br/wp-content/uploads/2008/11/clip-image002-thumb.gif" border="0" alt="clip_image002" width="379" height="144" /></a></p>
<p>Figura 2 – Aplicativo com pacotes dinâmicos carregando de um único pacote.</p>
<p>Abra o Delphi, crie um novo aplicativo e salve o projeto. Adicione os componentes necessários de forma natural, como se fosse um projeto comum e salve.</p>
<p>Agora você pode fechar seu projeto e criar um novo package, ou criá-lo no mesmo grupo de projetos. Para simplificar, vou usar a segunda opção. Crie uma Unit vazia dentro deste novo package.</p>
<p><a href="http://www.techtips.com.br/wp-content/uploads/2008/11/clip-image0016.gif"><img src="http://www.techtips.com.br/wp-content/uploads/2008/11/clip-image0016-thumb.gif" border="0" alt="clip_image001[6]" width="295" height="337" /></a></p>
<p>Você deverá percorrer TODOS os forms do seu projeto, vasculhando as cláusulas Uses para que todas as units referenciadas sejam adicionadas àquela unit do nosso pacote. Nosso objetivo será fazer com que o pacote importe todas essas units implicitamente para dentro dele, para que o executável tenha apenas ele como dependência. Para isso vá até Project -&gt; Options e escolha a opção “Directories/Conditionals”, altere o “Output directory” e o “DCP directory” para uma pasta onde estará seu executável (o “DCP directory” é necessário na hora da compilação do executável, pois ele vai procurar pelo arquivo .dcp do pacote, mas em tempo de execução, ele só precisará do arquivo .bpl), ou onde ele tenha acesso pelo path do Windows.</p>
<p><a href="http://www.techtips.com.br/wp-content/uploads/2008/11/clip-image003.jpg"><img style="0px" src="http://www.techtips.com.br/wp-content/uploads/2008/11/clip-image003-thumb.jpg" border="0" alt="clip_image003" width="515" height="349" /></a></p>
<p>É preferível deixar junto ao executável como numa pasta “bin” do seu projeto para facilitar a localização e distribuição, evitando um “bpl hell”. Clique em Ok e vá até aquela unit que você criou dentro do pacote. Adicione uma cláusula Uses a ela e coloque todas as units referenciadas pelo seu aplicativo.</p>
<p><a href="http://www.techtips.com.br/wp-content/uploads/2008/11/clip-image005.jpg"><img style="0px" src="http://www.techtips.com.br/wp-content/uploads/2008/11/clip-image005-thumb.jpg" border="0" alt="clip_image005" width="531" height="186" /></a></p>
<p>No diretório de saída que você acabou de configurar, coloque uma cópia da SysInit.dcu, que se encontra em $(BDS)\lib (ex: C:\Arquivos de programas\CodeGear\RAD Studio\5.0\lib). Esta unit faz-se necessária, pois se você tentar compilar seu projeto sem ela, vai disparar uma exceção, informando que não foi possível encontrar SysInit.dcu (lembre-se: o search path que você configurou sobrepõe o default do Delphi, daí ele não achar). Mesmo assim, esta unit não deve ser adicionada na sessão uses da unit do pacote, deverá apenas permanecer lá na pasta de destino. Vá até a sessão “requires” do seu pacote lá no Project manager e elimine TODAS as referências a outros packages, deixando-a vazia.</p>
<p>Agora compile seu pacote. Irá aparecer uma mensagem, dizendo que você deve incluir os packages da lista para manter compatibilidade com outros pacotes já instalados.</p>
<p><a href="http://www.techtips.com.br/wp-content/uploads/2008/11/clip-image006.gif"><img style="0px" src="http://www.techtips.com.br/wp-content/uploads/2008/11/clip-image006-thumb.gif" border="0" alt="clip_image006" width="389" height="305" /></a></p>
<p>É agora que vem o segredo: Escolha “Cancel” para que as units referenciadas sejam importadas para dentro de nosso pacote, e não as referências aos seus respectivos packages. Outro diálogo aparecerá com a mensagem: “If these changes are not applied, errors may occur when the package is loaded. Cancel changes?”.</p>
<p><a href="http://www.techtips.com.br/wp-content/uploads/2008/11/clip-image008.jpg"><img style="0px" src="http://www.techtips.com.br/wp-content/uploads/2008/11/clip-image008-thumb.jpg" border="0" alt="clip_image008" width="522" height="113" /></a></p>
<p>Escolha “Yes” agora. Toda vez que esse pacote for recompilado você deverá seguir estes passos.</p>
<p><a href="http://www.techtips.com.br/wp-content/uploads/2008/11/clip-image010.jpg"><img style="0px" src="http://www.techtips.com.br/wp-content/uploads/2008/11/clip-image010-thumb.jpg" border="0" alt="clip_image010" width="526" height="408" /></a></p>
<p>Se você verificar o resultado, poderá comprovar um package de até vários megabytes na pasta de destino (em um projeto que temos por aqui, está em torno de 13MB). Então, acabou? Ainda não, só mais uns ajustes no executável.</p>
<p>Considerando que você seguiu meu conselho e criou uma pasta só para os binários (“bin”, onde estarão .exe, .dcp, .bpl), selecione o projeto do executável agora, vá até Project -&gt; Options e escolha a opção “Directories/Conditionals”, lá em “Search path”, coloque o caminho da pasta Bin do seu projeto e faça o mesmo para o “Output directory”.</p>
<p><a href="http://www.techtips.com.br/wp-content/uploads/2008/11/clip-image012.jpg"><img style="0px" src="http://www.techtips.com.br/wp-content/uploads/2008/11/clip-image012-thumb.jpg" border="0" alt="clip_image012" width="554" height="349" /></a></p>
<p>Ainda nesta tela, escolha a opção “Packages”, marque a opção “Build with runtime pakages” e no Edit, limpe tudo, para adicionar apenas o nome do seu pacote.</p>
<p><a href="http://www.techtips.com.br/wp-content/uploads/2008/11/clip-image014.jpg"><img style="0px" src="http://www.techtips.com.br/wp-content/uploads/2008/11/clip-image014-thumb.jpg" border="0" alt="clip_image014" width="555" height="410" /></a></p>
<p>Clique em Ok e dê um build no seu aplicativo. Com isso, você já poderá notar uma redução de até 90% no tamanho do executável.</p>
<p><a href="http://www.techtips.com.br/wp-content/uploads/2008/11/clip-image015.gif"><img style="0px" src="http://www.techtips.com.br/wp-content/uploads/2008/11/clip-image015-thumb.gif" border="0" alt="clip_image015" width="552" height="143" /></a></p>
<p>Como já dito antes, para a distribuição do nosso aplicativo teste, apenas os 2 arquivos acima marcados serão necessários.</p>
<h3>Conclusão</h3>
<p>Quais as vantagens que podemos tirar deste método? Teremos todas as vantagens de se utilizar pacotes dinâmicos em um aplicativo, como velocidade na compilação (lembre-se que na maioria das vezes, você compilará apenas o código associado diretamente ao seu aplicativo, pois o código dos componentes já está embutido no pacote), executáveis e dlls muito menores (muito mais simples e rápido para atualizar seu aplicativo junto aos clientes) e maior facilidade para implementação de plugins, seja com dlls ou bpls. Se você colocar regras de negócio em um pacote ou fizer uso de rotinas muito sigilosas, poderá distribuir apenas os bpls do pacote livremente entre os desenvolvedores do projeto sem medo, pois estará fazendo uso do encapsulamento de código a seu favor.</p>
<p>E as desvantagens? Se você considerar todos os benefícios desta abordagem, o fato de ter que atualizar um pacote de 13MB (se compactar pode cair para 4MB ou 5MB) toda vez que mudar algum componente não pesará tão contra assim.</p>
<p>Este exemplo criou um único pacote com todas as units utilizadas pelo aplicativo, mas se você preferir poderá criar 2, 3 ou quantos pacotes precisar, separando-os por categoria, como pacotes de componentes visuais, acesso a dados, regras de negócio ou outra categoria que for necessária para seu projeto.</p>
<p>Este é o meu primeiro post, e espero que seja útil para quem precisar aplicar tais conceitos.</p>
<p><center>&copy; <a href="http://">TechTips</a></center></p>]]></content:encoded>
			<wfw:commentRss>http://www.techtips.com.br/programacao/modularizao-de-aplicativos-single-package/feed/</wfw:commentRss>
		<slash:comments>25</slash:comments>
		</item>
		<item>
		<title>Anonymous Methods e Closures no Delphi 2009</title>
		<link>http://www.techtips.com.br/programacao/delphi/linguagem-delphi/anonymous-methods-e-closures-no-delphi-2009/</link>
		<comments>http://www.techtips.com.br/programacao/delphi/linguagem-delphi/anonymous-methods-e-closures-no-delphi-2009/#comments</comments>
		<pubDate>Fri, 29 Aug 2008 03:53:39 +0000</pubDate>
		<dc:creator>Leonel Togniolli</dc:creator>
				<category><![CDATA[Linguagem Delphi]]></category>

		<guid isPermaLink="false">http://www.techtips.com.br/programacao/delphi/linguagem-delphi/anonymous-methods-e-closures-no-delphi-2009/</guid>
		<description><![CDATA[Já conhecemos a sintaxe dos anonymous methods do Delphi 2009. A parte interessante deste novo recurso é que eles são closures. Closure é a união do código com o seu escopo. Isso quer dizer que o novo método tem acesso às variáveis locais do método que o criou, mesmo depois que ele terminou. Vamos ver [...]]]></description>
			<content:encoded><![CDATA[<p>Já conhecemos a sintaxe dos <a href="http://www.techtips.com.br/programacao/delphi/linguagem-delphi/anonymous-methods-no-delphi-2009/">anonymous methods</a> do Delphi 2009. A parte interessante deste novo recurso é que eles são <a href="http://en.wikipedia.org/wiki/Closure_(computer_science)">closures</a>.</p>
<p>Closure é a união do código com o seu escopo. Isso quer dizer que o novo método tem acesso às variáveis locais do método que o criou, mesmo depois que ele terminou. Vamos ver como isso funciona com um exemplo:</p>
<pre>type
  TContador = reference to function: Integer;

function CriaContador(Inicial, Final: Integer): TContador;
var
  i: Integer;
begin
  i := Inicial;
  Result := function: Integer
  begin
    Result := i;
    Inc(i);
    if i &gt; Final then
      i := Inicial;
  end;
end;

var
  Contador: TContador;
  i: Integer;
begin
  Contador := CriaContador(5, 12);
  for i := 0 to 20 do
    WriteLn(Contador);
end.</pre>
<p>Antes de ver a listagem da saída do programa, Vamos entender o código. TContador é um tipo que representa uma referência a uma função que retorna um número. Neste caso, vai retornar uma sequência de números, um número novo cada vez que for chamada. CriaContador é uma função que retorna um método desse tipo, recebendo os valores inicial e final que a sequência vai ter. Repare que o corpo de CriaContador tem apenas duas linhas de código que serão executadas quando ela for chamada: ela inicializa o contador, e atribui um novo método para o resultado.</p>
<p>No corpo do programa criamos um novo contador na faixa 5 até 12, e chamamos essa função 21 vezes, escrevendo o resultado no console.  Em cada chamada da função, ela retorna o valor atual de i, o incrementa, e caso tenha passado do valor final, volta ao primeiro.</p>
<p>Quais serão os 21 números escritos no console?</p>
<pre>5
6
7
8
9
10
11
12
5
6
7
8
9
10
11
12
5
6
7
8
9</pre>
<p>Ou seja, o programa funciona exatamente como descrevi.</p>
<p>Cada instância do método captura o escopo daquele momento. Se criarmos dois contadores:</p>
<pre>var
  Contador, Contador2: TContador;
  i: Integer;
begin
  Contador := CriaContador(5, 8);
  Contador2 := CriaContador(1, 3);
  for i := 0 to 5 do
    WriteLn(Contador,':',Contador2);
end.</pre>
<p>podemos ver que eles funcionam de forma completamente independente:</p>
<pre>5:1
6:2
7:3
8:1
5:2
6:3</pre>
<p>Essa é uma nova técnica possível no Delphi 2009. Para implementar o equivalente sem este recurso, seria necessário criar classes para o contador, construir instâncias e liberá-las. Ou seja, muito mais código e complicação.</p>
<p>O Craig Stuntz <a href="http://blogs.teamb.com/craigstuntz/2008/08/28/37831">escreveu um exemplo</a> muito interessante utilizando esse método pra implementar o <a href="http://pt.wikipedia.org/wiki/Crivo_de_Erat%C3%B3stenes">Crivo de Eratóstenes</a>. Ele entrou no assunto da técnica de <a href="http://en.wikipedia.org/wiki/Currying">currying</a>, que vai ficar para o próximo artigo.</p>
<p><center>&copy; <a href="http://www.techtips.com.br">TechTips</a></center></p>]]></content:encoded>
			<wfw:commentRss>http://www.techtips.com.br/programacao/delphi/linguagem-delphi/anonymous-methods-e-closures-no-delphi-2009/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Anonymous Methods no Delphi 2009</title>
		<link>http://www.techtips.com.br/programacao/delphi/linguagem-delphi/anonymous-methods-no-delphi-2009/</link>
		<comments>http://www.techtips.com.br/programacao/delphi/linguagem-delphi/anonymous-methods-no-delphi-2009/#comments</comments>
		<pubDate>Thu, 28 Aug 2008 18:27:09 +0000</pubDate>
		<dc:creator>Leonel Togniolli</dc:creator>
				<category><![CDATA[Linguagem Delphi]]></category>

		<guid isPermaLink="false">http://www.techtips.com.br/programacao/delphi/linguagem-delphi/anonymous-methods-no-delphi-2009/</guid>
		<description><![CDATA[Um dos novos recursos no Delphi 2009 é anonymous methods. É também chamado de “referências a métodos”, pois a declaração de um tipo procedural é feita com a sintaxe “reference to function/procedure”: type TComparaString = reference to function(const S1, S2: string): Integer; Esse tipo pode ser usado como qualquer outro tipo procedural: procedure TLista.Ordena(Compara: TComparaString); [...]]]></description>
			<content:encoded><![CDATA[<p>Um dos novos recursos no Delphi 2009 é anonymous methods. É também chamado de “referências a métodos”, pois a declaração de um <a href="http://www.techtips.com.br/programacao/delphi/linguagem-delphi/guardando-mtodos-funces-e-procedimentos-em-variveis-com-tipos-procedurais/">tipo procedural</a> é feita com a sintaxe “reference to function/procedure”:</p>
<pre>type
  TComparaString = reference to function(const S1, S2: string): Integer;</pre>
<p>Esse tipo pode ser usado como qualquer outro tipo procedural:</p>
<pre>procedure TLista.Ordena(Compara: TComparaString);
var
  i, j: Integer;
begin
  for i := 0 to FItems.Count - 2 do
    for j := FItems.Count - 1 downto i + 1 do
      if Compara(FItems[j], FItems[i]) &lt; 0 then
         Troca(i, j);
end;</pre>
<p>(Perdoem-me o <a href="http://en.wikipedia.org/wiki/Bubble_sort">Bubble Sort</a>)</p>
<p>Não precisamos mais declarar um método separadamente para cada forma diferente de ordenação que for necessária. O código abaixo ordena uma lista alfabeticamente, depois de forma inversa, e finalmente de acordo com o tamanho da string:</p>
<pre>  Lista := TLista.Create;
  try
    Lista.Adiciona('Um');
    Lista.Adiciona('Dois');
    Lista.Adiciona('Tres');
    Lista.Adiciona('Quatro');
    Lista.Adiciona('Cinco');
    Lista.Ordena(function(const S1, S2: string): Integer
                 begin
                   Result := CompareStr(S1, S2);
                 end);
    WriteLn(Lista.Texto);
    Lista.Ordena(function(const S1, S2: string): Integer
                 begin
                   Result := CompareStr(S2, S1);
                 end);
    WriteLn(Lista.Texto);
    Lista.Ordena(function(const S1, S2: string): Integer
                 begin
                   Result := Length(S1) - Length(S2);
                   if Result = 0 then
                     Result := CompareStr(S1, S2);
                 end);
    WriteLn(Lista.Texto);
  finally
    Lista.Free;
  end;</pre>
<p>A resultado do programa é:</p>
<pre>Cinco
Dois
Quatro
Tres
Um

Um
Tres
Quatro
Dois
Cinco

Um
Dois
Tres
Cinco
Quatro</pre>
<p>Até aí, o recurso não é nada demais – permite economizar algumas linhas em troca de uma sintaxe discutivelmente mais confusa. Ele fica realmente interessante quando se nota que é, de fato, uma <a href="http://en.wikipedia.org/wiki/Closure_(computer_science)">Closure</a>, que exploraremos no próximo artigo.</p>
<p><center>&copy; <a href="http://www.techtips.com.br">TechTips</a></center></p>]]></content:encoded>
			<wfw:commentRss>http://www.techtips.com.br/programacao/delphi/linguagem-delphi/anonymous-methods-no-delphi-2009/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Anunciado Delphi 2009</title>
		<link>http://www.techtips.com.br/programacao/delphi/anunciado-delphi-2009-2/</link>
		<comments>http://www.techtips.com.br/programacao/delphi/anunciado-delphi-2009-2/#comments</comments>
		<pubDate>Mon, 25 Aug 2008 17:02:39 +0000</pubDate>
		<dc:creator>Leonel Togniolli</dc:creator>
				<category><![CDATA[Delphi]]></category>

		<guid isPermaLink="false">http://www.techtips.com.br/programacao/delphi/anunciado-delphi-2009-2/</guid>
		<description><![CDATA[O Delphi 2009 acaba de ser anunciado. Já está disponível para pré-venda, e acredito que já esteja disponível para download para quem optar por Eletronic Software Delivery em pouco tempo. Apesar de o principal novo recurso ser o total suporte de Unicode na VCL, vários outros novos recursos chamam a atenção: Novos controles na VCL, [...]]]></description>
			<content:encoded><![CDATA[<p>O <a href="http://www.codegear.com/br/products/delphi/win32">Delphi 2009</a> acaba de ser <a href="http://www.embarcadero.com/news/press_releases/delphicppbuilder.html">anunciado</a>. Já está disponível para pré-venda, e acredito que já esteja disponível para download para quem optar por <em>Eletronic Software Delivery </em>em pouco tempo.</p>
<p>Apesar de o principal novo recurso ser o total suporte de Unicode na VCL, vários outros novos recursos chamam a atenção:</p>
<ul>
<li>Novos controles na VCL, com destaque ao Ribbons estilo Office 2007.</li>
<li>Melhorias na ImageList, incluindo suporte a PNG.</li>
<li>Novos recursos de linguagem, com destaque a Generics e Anonymous Methods.</li>
<li>VCL pra Web atualizada com suporte a AJAX e Silverlight.</li>
<li>DataSnap 2009, que simplifica o desenvolvimento de aplicações três camadas sem uso de COM.</li>
</ul>
<p>Vale a pena conferir a <a href="http://dn.codegear.com/article/38459">lista de componentes de terceiros</a> que já foram atualizados para ter suporte ao Delphi 2009.</p>
<p>Pretendo detalhar os novos recursos em futuros artigos, portanto aguarde atualizações.</p>
<p><center>&copy; <a href="http://www.techtips.com.br">TechTips</a></center></p>]]></content:encoded>
			<wfw:commentRss>http://www.techtips.com.br/programacao/delphi/anunciado-delphi-2009-2/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Pegando a Data da &#218;ltima Leitura de um arquivo</title>
		<link>http://www.techtips.com.br/programacao/delphi/pegando-a-data-da-ltima-leitura-de-um-arquivo/</link>
		<comments>http://www.techtips.com.br/programacao/delphi/pegando-a-data-da-ltima-leitura-de-um-arquivo/#comments</comments>
		<pubDate>Tue, 02 Oct 2007 17:30:32 +0000</pubDate>
		<dc:creator>Feijo</dc:creator>
				<category><![CDATA[Delphi]]></category>
		<category><![CDATA[Linguagem Delphi]]></category>

		<guid isPermaLink="false">http://www.techtips.com.br/programacao/delphi/pegando-a-data-da-ltima-leitura-de-um-arquivo/</guid>
		<description><![CDATA[Função pequena e útil, descobre quando aquele arquivo foi acessado pela última vez. &#160; function FileAccessTime(FileName: String): TDateTime;var&#160; FileHandle: Integer;&#160; LTime,&#160; FTimeA: TFileTime;&#160; STime: TSystemTime;begin&#160; FileHandle := FileOpen(FileName,fmShareDenyNone); &#160; if FileHandle &#62;= 0 then&#160; begin&#160;&#160;&#160; // Accessado&#160;&#160;&#160; GetFileTime(FileHandle,nil, @FTimeA, nil);&#160;&#160;&#160; FileClose(FileHandle);&#160;&#160;&#160; FileTimeToLocalFileTime(FTimeA,LTime); &#160;&#160;&#160; if FileTimeToSystemTime(LTime,STime) then&#160;&#160;&#160; begin&#160;&#160;&#160;&#160;&#160; Result := EncodeDate(STime.wYear,STime.wMonth,STime.wDay);&#160;&#160;&#160;&#160;&#160; Result := Result + EncodeTime(STime.wHour,STime.wMinute,STime.wSecond,STime.wMilliSeconds);&#160;&#160;&#160; [...]]]></description>
			<content:encoded><![CDATA[<p>Função pequena e útil, descobre quando aquele arquivo foi acessado pela última vez.
<p>&nbsp;
<p>function FileAccessTime(FileName: String): TDateTime;<br />var<br />&nbsp; FileHandle: Integer;<br />&nbsp; LTime,<br />&nbsp; FTimeA: TFileTime;<br />&nbsp; STime: TSystemTime;<br />begin<br />&nbsp; FileHandle := FileOpen(FileName,fmShareDenyNone);
<p>&nbsp; if FileHandle &gt;= 0 then<br />&nbsp; begin<br />&nbsp;&nbsp;&nbsp; // Accessado<br />&nbsp;&nbsp;&nbsp; GetFileTime(FileHandle,nil, @FTimeA, nil);<br />&nbsp;&nbsp;&nbsp; FileClose(FileHandle);<br />&nbsp;&nbsp;&nbsp; FileTimeToLocalFileTime(FTimeA,LTime);
<p>&nbsp;&nbsp;&nbsp; if FileTimeToSystemTime(LTime,STime) then<br />&nbsp;&nbsp;&nbsp; begin<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Result := EncodeDate(STime.wYear,STime.wMonth,STime.wDay);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Result := Result + EncodeTime(STime.wHour,STime.wMinute,STime.wSecond,STime.wMilliSeconds);<br />&nbsp;&nbsp;&nbsp; end;<br />&nbsp; end;<br />end;
<p>&nbsp;
<p>procedure TForm1.Button1Click(Self);
<p>begin
<p>&nbsp; ShowMessage(DateTimeToStr(FileAccessTime(&#8216;c:\windows\areia.bmp&#8217;));
<p>end;</p>
<p><center>&copy; <a href="http://delphi.feijo.pro.br">TechTips</a></center></p>]]></content:encoded>
			<wfw:commentRss>http://www.techtips.com.br/programacao/delphi/pegando-a-data-da-ltima-leitura-de-um-arquivo/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Video Aula ASP.Net 2.0 com Delphi 2007 e BlackfishSQL</title>
		<link>http://www.techtips.com.br/programacao/delphi/aspnet/video-aula-aspnet-20-com-delphi-2007-e-blackfishsql/</link>
		<comments>http://www.techtips.com.br/programacao/delphi/aspnet/video-aula-aspnet-20-com-delphi-2007-e-blackfishsql/#comments</comments>
		<pubDate>Thu, 13 Sep 2007 16:27:04 +0000</pubDate>
		<dc:creator>Leonel Togniolli</dc:creator>
				<category><![CDATA[Asp.Net]]></category>
		<category><![CDATA[Video Aulas]]></category>

		<guid isPermaLink="false">http://www.techtips.com.br/programacao/delphi/aspnet/video-aula-aspnet-20-com-delphi-2007-e-blackfishsql/</guid>
		<description><![CDATA[Essa é uma introdução que mostra como criar uma simples aplicação em ASP.Net 2.0 com o Delphi 2007 mostrando dados de uma tabela em um servidor de banco de dados BlackfishSQL. Também mostra os novos layouts que estão incluidos on Delphi 2007, usando CSS e MasterPages. Veja o vídeo aqui. &#169; TechTips]]></description>
			<content:encoded><![CDATA[<p>Essa é uma introdução que mostra como criar uma simples aplicação em ASP.Net 2.0 com o Delphi 2007 mostrando dados de uma tabela em um servidor de banco de dados BlackfishSQL. Também mostra os novos layouts que estão incluidos on Delphi 2007, usando CSS e MasterPages.</p>
<p>Veja o vídeo <a href="http://www.techtips.com.br/arquivos/aspnet20delphiblackfish/aspnet20delphiblackfish.html">aqui</a>.</p>
<p><center>&copy; <a href="http://www.techtips.com.br">TechTips</a></center></p>]]></content:encoded>
			<wfw:commentRss>http://www.techtips.com.br/programacao/delphi/aspnet/video-aula-aspnet-20-com-delphi-2007-e-blackfishsql/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>Novidades em Banco de Dados no Delphi 2007 para .Net e RAD Studio 2007</title>
		<link>http://www.techtips.com.br/programacao/delphi/novidades-em-banco-de-dados-no-delphi-2007-para-net-e-rad-studio-2007/</link>
		<comments>http://www.techtips.com.br/programacao/delphi/novidades-em-banco-de-dados-no-delphi-2007-para-net-e-rad-studio-2007/#comments</comments>
		<pubDate>Wed, 12 Sep 2007 15:18:39 +0000</pubDate>
		<dc:creator>Leonel Togniolli</dc:creator>
				<category><![CDATA[Bancos de Dados]]></category>
		<category><![CDATA[Delphi]]></category>

		<guid isPermaLink="false">http://www.techtips.com.br/programacao/delphi/novidades-em-banco-de-dados-no-delphi-2007-para-net-e-rad-studio-2007/</guid>
		<description><![CDATA[Já falei sobre as novidades na linguagem, em ASP.Net e no ECO IV no Delphi 2007 para .Net e RAD Studio 2007. O próximo tópico é novidades na área de Banco de Dados. BlackfishSQL para .Net BlackfishSQL é um novo banco de dados, para .Net, escrito 100% em código gerenciado, sem qualquer dependência de DLLs [...]]]></description>
			<content:encoded><![CDATA[<p>Já falei sobre as <a href="http://www.techtips.com.br/programacao/delphi/novidades-no-novo-delphi-2007-para-netrad-studio-2007/">novidades na linguagem, em ASP.Net e no ECO IV no Delphi 2007 para .Net e RAD Studio 2007</a>. O próximo tópico é novidades na área de Banco de Dados.</p>
<h2>BlackfishSQL para .Net</h2>
<p><a href="http://www.codegear.com/products/blackfish">BlackfishSQL</a> é um novo banco de dados, para .Net, escrito 100% em código gerenciado, sem qualquer dependência de DLLs do windows. Você já pode ter ouvido falar sobre o BlackfishSQL com os nomes NDataStore e SqlDataStore. </p>
<p>Ele possui um código unificado com o BlackfishSQL para Java, anteriormente JDataStore, sendo completamente compatível em protocolo e formato do arquivo de banco de dados. Na prática, ao usar BlackfishSQL, você pode ter um servidor em qualquer plataforma que possua uma VM .Net ou Java. Outro ponto importante é que, apesar de BlackfishSQL para .Net ser um novo produto, é na prática versão&nbsp;8.0&nbsp;(seguindo o JDataStore 7), tendo um núcleo maduro, testado e já bastante utilizado.</p>
<p>Um dos recursos mais interessantes do BlackfishSQL é poder escrever Stored Procedures e triggers em Delphi, dentro da IDE, como você sempre fez com suas aplicações. Isso permite também depurar as stored procedures usando o debugger do Delphi, como se você estivesse depurando sua própria aplicação. Basta colocar os breakpoints e iniciar a sessão de depuração. É sem dúvida uma forma muito mais eficiente e produtiva de colocar sua regra de negócio no banco de dados do que aprender um dialeto SQL específico dos outros bancos de dados.</p>
<p>Existem três drivers para o BlackfishSQL. Os dois primeiros são para aplicações .Net, sendo um Local, onde o servidor roda no próprio processo e acessa o banco de dados diretamente, e um Remoto, que utiliza TCP/IP para acessar um servidor Blackfish rodando na mesma máquina ou remotamente. É interessante notar que&nbsp;a distribuição de uma aplicação que utiliza um driver Ado.Net Local para Blackfish é copiar e rodar &#8211; não é necessária nenhuma configuração ou instalação.</p>
<p>Isso torna BlackfishSQL para .Net uma escolha bastante interessante para distribuir aplicações Asp.Net &#8211; o seu servidor de hospedagem não precisa ter um servidor de banco de dados instalado, e você não precisa pagar a mais por isso &#8211; basta copiar&nbsp;a versão Local do driver .Net, o arquivo de banco de dados (ou deixar sua aplicação criá-lo com os novos recursos de metadados&nbsp;que vou mostrar mais pra frente), e sua aplicação web está pronta pra funcionar.</p>
<p>O <a href="http://cc.codegear.com/Item/24980">Blackfish SQL Developer Guide</a> está disponível para download no CodeCentral &#8211; 205 páginas de documentação, exemplos e bastante informação pra quem está interessado em ver o que o BlackfishSQL oferece.</p>
<h2>DbxClient</h2>
<p>A terceira forma de acessar um servidor BlackfishSQL é um protocolo JSON/RPC implementado por um novo driver dbExpress, chamado DbxClient, através de aplicações VCL para Win32 ou .Net. Isso permite você acessar um servidor BlackfishSQL, com suas regras de negócio escritas em Delphi, através de clientes Win32, sem precisar depender do framework .Net em cada estação.</p>
<p>Isso torna BlackfishSQL o nono banco de dados que dbExpress suporta diretamente nessa nova versão, para .Net e Win32. DbxClient é mais um driver escrito em Delphi e que possui todo o código fonte incluído no produto.</p>
<p>Por enquanto BlackfishSQL é o unico servidor que é acessível pelo protocolo DbxClient, mas aguarde notícias sobre esse assunto &#8211; na minha opinião, é um tópico bastante promissor.</p>
<h2>DbxReadOnlyMetadata e DbxMetadata</h2>
<p>DBX4 continua a evoluir, e desta vez é criando uma base sólida de metadados bastante ricos, completamente escrita em Delphi e com o código fonte disponível.</p>
<p>DbxReadOnlyMetadata é uma extensão do dbExpress permitindo ler metadados, de uma forma fácil, prática e comum, de qualquer um dos nove banco de dados suportados. Está disponível em Win32 e .Net. Além de informações sobre a conexão (se ela diferencia&nbsp;maisculas e minusculas, se possui schemas, quais os caracteres de inicio e fim de aspas, etc), é possível obter as seguintes informações sobre o banco:</p>
<ol>
<li>Tipos de Dados
<li><strong>Catalogs</strong>
<li><strong>Schemas</strong>
<li>Tabelas
<li><strong>Views</strong>
<li><strong>Synonms</strong>
<li>Colunas (de tabelas, views, etc)
<li>Indices
<li>Campos&nbsp;que compõe&nbsp;cada indice
<li>Chaves Extrangeiras
<li>Campos que compõe cada chave extrangeira
<li>Stored Procedures
<li><strong>Código Fonte de Stored Procedures</strong>
<li>Parametros de Stored Procedures
<li><strong>Package Stored Procedures</strong>
<li><strong>Código Fonte de Package Stored Procedures</strong>
<li><strong>Parametros de Package Stored Procedures</strong>
<li>Usuários
<li><strong>Roles</strong>
<li><strong>Palavras Reservadas</strong></li>
</ol>
<p>Os itens em negrito são comandos novos de metadatados introduzidos nessa nova versão. Todos eles podem ser acessados&nbsp;utilizando uma query com o CommandType Metadata, e o resultado vem como um resultado comum de query, podem ser manipulado com os componentes que já estamos acostumados, ou exibido em grid e assim por diante.</p>
<p>DbxMetadata é a versão de escrita de metadados. Ela gera commandos SQL de Create, Alter e Drop de acordo com coleções que são passadas, gerando tabelas, indices, e vários outros objetos. Extremamente útil para quem quer escrever um aplicação independende de banco de dados, não precisando se preocupar com o sintaxe especifica de cada banco.&nbsp;Criar uma tabela é mais ou menos assim:</p>
<pre>begin
  MetaDataTable := TDBXMetaDataTable.Create;
  MetaDataTable.TableName := 'TABELA';
  MetaDataTable.AddColumn(TDBXInt32Column.Create(’Coluna1′));
  MetaDataTable.AddColumn(TDBXDecimalColumn.Create(’Coluna2′, 10, 2));
  MetaDataTable.AddColumn(TDBXUnicodeCharColumn.Create(’Coluna3′, 32));
  MetaDataProvider.CreateTable(MetaDataTable);
end;</pre>
<p>A parte de escrita de DbxMetadata só está disponível para a plataforma .Net nessa versão, mas nada impede que seja disponibilizado para Win32 no futuro.</p>
<h2>Certified Test Suite e Geradores de Dados</h2>
<p>Tendo como objetivo a melhor&nbsp;qualidade possível dos drivers dbExpress incluidos no produto e dos de terceiros, foi criada uma suite de testes automatizados de certificação para dbExpress. Completamente escrita em Delphi e com todo o código fonte disponível. Não é só quem escreve drivers que vai se interessar em aproveitar essa suite &#8211; as extensões para o DUnit e as rotinas para trabalhar com dados podem ser usadas por qualquer um que efetue testes automatizados em aplicações de bancos de dados &#8211; ou quem está pensando em começar.</p>
<p>Entre o conteúdo dessa suíte, vale um destaque para o TDbxDataGenerator e classes relacionadas. Ela auxilia o controle de qualidade gerando valores para popular tabelas para testes, depois que foram criadas com as rotinas de DbxMetadata mostradas acima, de acordo com o tipo de cada coluna. </p>
<h2>AdoDbxClient</h2>
<p>Para quem escreve aplicações Asp.Net ou ECO, está disponível o AdoDbxClient. Ele é um provider Ado.Net 2.0 nativo que permite a utilização de drivers dbExpress diretamente em Ado.Net 2.0. Não é mais necessário utilizar&nbsp;classes ou componentes diferentes como era com o BDP &#8211; basta programar utilizando DbConnection, DbCommand e afims, de uma forma independente de banco de dados, podendo determinar em tempo de execução se será utilizado os providers do framework .net (SqlClient, OracleClient), os do BlackfishSQL para ADO.Net (Local e Remote), ou qualquer um dos nove drivers suportados em dbExpress.</p>
<h2>E Tudo o Mais</h2>
<p>Além de tudo isso existem diversas pequenas melhorias e correções de problemas, parte de&nbsp;um processo constante de aperfeiçoamento.</p>
<p>Essa versão, apesar de ser um produto .Net completando o RAD Studio com o Delphi para Win32 e C++Builder já existentes, possui recursos que podem interessar a vários tipos de desenvolvedores, inclusive os que só trabalham com código nativo. Não deixe de <a href="http://cc.codegear.com/Free.aspx?id=24966">conferir a nova versão</a>!</p>
<p><center>&copy; <a href="http://www.techtips.com.br">TechTips</a></center></p>]]></content:encoded>
			<wfw:commentRss>http://www.techtips.com.br/programacao/delphi/novidades-em-banco-de-dados-no-delphi-2007-para-net-e-rad-studio-2007/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
	</channel>
</rss>

<!-- Dynamic Page Served (once) in 0.842 seconds -->
