<?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>Juliano Ribeiro &#187; Delphi</title>
	<atom:link href="http://julianoribeiro.com.br/blog/category/desenvolvimento/delphi/feed/" rel="self" type="application/rss+xml" />
	<link>http://julianoribeiro.com.br/blog</link>
	<description>Development and Design</description>
	<lastBuildDate>Tue, 31 Jan 2012 11:40:50 +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>[Delphi] Criando campos dinâmicos</title>
		<link>http://julianoribeiro.com.br/blog/delphi-criando-campos-dinamicos/</link>
		<comments>http://julianoribeiro.com.br/blog/delphi-criando-campos-dinamicos/#comments</comments>
		<pubDate>Mon, 06 Dec 2010 14:02:05 +0000</pubDate>
		<dc:creator>Juliano Ribeiro</dc:creator>
				<category><![CDATA[Básico]]></category>
		<category><![CDATA[Delphi]]></category>
		<category><![CDATA[Desenvolvimento]]></category>
		<category><![CDATA[Pessoal]]></category>
		<category><![CDATA[Campo dinâmico]]></category>
		<category><![CDATA[TClientDataSet]]></category>
		<category><![CDATA[TField]]></category>

		<guid isPermaLink="false">http://julianoribeiro.com.br/blog/?p=469</guid>
		<description><![CDATA[Bom dia meu povo. Dia desses precisei criar dinamicamente algumas colunas em um TClientDataset. Normalmente um uso a propriedade FieldDefs por ser mais fácil de manipular e evitar problemas de MemoryLeaks. Mas nesse caso específico eu precisava dos campos como novos objetos, portanto tinham de herdar diretamente de TField. Assim, após algum trabalho, cheguei no [...]]]></description>
			<content:encoded><![CDATA[<p>Bom dia meu povo.</p>
<p>Dia desses precisei criar dinamicamente algumas colunas em um <strong>TClientDataset</strong>. Normalmente um uso a propriedade <strong>FieldDefs </strong>por ser mais fácil de manipular e evitar problemas de <strong>MemoryLeaks</strong>. Mas nesse caso específico eu precisava dos campos como novos objetos, portanto tinham de herdar diretamente de <strong>TField</strong>. Assim, após algum trabalho, cheguei no resultado abaixo.</p>
<pre class="brush: delphi;">
procedure CriaField_Integer(cFieldName: String; cDisplayLabel: String; fFieldKind: TFieldKind; nDisplayWidth: Integer; var ds: TClientDataSet; lVisible: Boolean);
begin
    with TIntegerField.Create(Self) do
    begin
        FieldName      := cFieldName;
        Name           := ds.Name + UpperCase(FieldName);
        FieldKind      := fFieldKind;
        Size           := 0;
        DisplayLabel   := cDisplayLabel;
        DisplayWidth   := nDisplayWidth;
        Visible        := lVisible;
        DataSet        := ds;
    end;
end;

procedure CriaField_Boolean(cFieldName: String; cDisplayLabel: String; fFieldKind: TFieldKind; nDisplayWidth: Integer; var ds: TClientDataSet; lVisible: Boolean);
begin
    with TBooleanField.Create(Self) do
    begin
        FieldName      := cFieldName;
        Name           := ds.Name + UpperCase(FieldName);
        FieldKind      := fFieldKind;
        DisplayLabel   := cDisplayLabel;
        DisplayWidth   := nDisplayWidth;
        Visible        := lVisible;
        DataSet        := ds;
    end;
end;

procedure CriaField_DateTime(cFieldName, cDisplayLabel: String; fFieldKind: TFieldKind; nDisplayWidth: Integer; var ds: TClientDataSet; lVisible: Boolean);
begin
    with TDateTimeField.Create(Self) do
    begin
        FieldName     := cFieldName;
        Name          := ds.Name + UpperCase(FieldName);
        FieldKind     := fFieldKind;
        Size          := 0;
        DisplayLabel  := cDisplayLabel;
        DisplayWidth  := nDisplayWidth;
        Visible       := lVisible;
        DataSet       := ds;
    end;
end;

procedure CriaField_Float(cFieldName: String; cDisplayLabel: String; fFieldKind: TFieldKind; nPrecision, nDisplayWidth: Integer; cDisplayFormat: String; var ds: TClientDataSet; lVisible: Boolean);
begin
    with TFloatField.Create(Self) do
    begin
        FieldName     := cFieldName;
        Name          := ds.Name + UpperCase(FieldName);
        FieldKind     := fFieldKind;
        Size          := 0;
        Precision     := nPrecision;
        DisplayLabel  := cDisplayLabel;
        DisplayWidth  := nDisplayWidth;
        DisplayFormat := cDisplayFormat;
        Visible       := lVisible;
        DataSet       := ds;
    end;
end;
</pre>
<p>Como por aqui não tem muita orientação à objetos, não fiz muita <strong><em>firula</em></strong>, quem sabe eu dou uma melhorada nesse código outro dia, ou vocês mesmos o fazem.</p>
]]></content:encoded>
			<wfw:commentRss>http://julianoribeiro.com.br/blog/delphi-criando-campos-dinamicos/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Padrão Builder com Delphi</title>
		<link>http://julianoribeiro.com.br/blog/padrao-builder-com-delphi/</link>
		<comments>http://julianoribeiro.com.br/blog/padrao-builder-com-delphi/#comments</comments>
		<pubDate>Wed, 06 Oct 2010 18:58:36 +0000</pubDate>
		<dc:creator>Juliano Ribeiro</dc:creator>
				<category><![CDATA[Delphi]]></category>
		<category><![CDATA[Orientação à Objetos]]></category>
		<category><![CDATA[Pessoal]]></category>
		<category><![CDATA[SQL]]></category>
		<category><![CDATA[Builder]]></category>
		<category><![CDATA[Design Patterns]]></category>
		<category><![CDATA[Orientação à Objeto]]></category>
		<category><![CDATA[Padrão de Projetos]]></category>
		<category><![CDATA[POO]]></category>
		<category><![CDATA[Programação]]></category>

		<guid isPermaLink="false">http://julianoribeiro.com.br/blog/?p=431</guid>
		<description><![CDATA[Voltando a falar de programação, hoje vamos continuar a falar da orientação à objetos dentro do Delphi. Apesar de estar estudando Java já tem algum tempo, eu trabalho com Delphi desde de sua versão 2.0, então fica bem difícil não querer aplicar tudo o que aprendi sobre o assunto na linguagem que tenho mais afinidade. [...]]]></description>
			<content:encoded><![CDATA[<p>Voltando a falar de programação, hoje vamos continuar a falar da orientação à objetos dentro do Delphi. Apesar de estar estudando Java já tem algum tempo, eu trabalho com Delphi desde de sua versão 2.0, então fica bem difícil não querer aplicar tudo o que aprendi sobre o assunto na linguagem que tenho mais afinidade.<br />
<span id="more-431"></span><br />
O padrão de projeto <strong>Builder</strong>, nada mais é que um construtor especializado, que executa determinadas ações sempre que precisa construir um novo objeto. Vamos imaginar, por exemplo, que você criou em sua classe de serviços, um método <strong>getItemById</strong>, que tem como parâmetro óbvio o <strong>ID</strong> e retorna um objeto da classe referenciada. Digamos que seria um código semelhante à esse:</p>
<pre class="brush: delphi;">
function TServicoMinhaClasse.getMinhaClasseById(Id: Integer): TMinhaClasse;
var
   cls: TMinhaClasse;
begin
   cls := TMinhaClasse.Create;
   Result := cls;
end;
</pre>
<p>Esse seria um código legal, se a classe não tivesse atributos. Para piorar esses dados ficam guardados em banco de dados. Portanto, eu preciso criar a conexão (ou usar uma existente) e criar uma nova consulta ao banco, configurando o banco. Para o nosso exemplo, vamos imaginar que a MinhaClasse tenha código e descrição somente. O código da unit da classe ficaria como o abaixo:</p>
<pre class="brush: delphi;">
unit unMinhaClasse;

interface

type
   TMinhaClasse = class(TObject)

   private
      FDescricao: String;
      FID: Integer;
      procedure SetID(const Value: Integer);
      procedure SetDescricao(const Value: String);
   public
      property ID: Integer read FID write SetID;
      property Descricao: String read FDescricao write SetDescricao;
   end;

implementation

{ TMinhaClasse }

procedure TMinhaClasse.SetID(const Value: Integer);
begin
  FID := Value;
end;

procedure TMinhaClasse.SetDescricao(const Value: String);
begin
  FDescricao := Value;
end;

end.
</pre>
<p>Assim, para preencher essas propriedades, vamos modificar o corpo da nossa função para algo assim:</p>
<pre class="brush: delphi;">
(...)
var
   qry: TSQLQuery;
begin
   cls := TMinhaClasse.Create;

   qry := TSQLQuery.Create;

   try
      qry.Database    := dModule.Database;
      qry.Transaction := dModule.Transaction;
      qry.SQL.Add('select * from tabela where id = :id');
      qry.ParamByName('id').AsInteger := Id;
      qry.Open;

      if not qry.IsEmpty then
      begin
         cls.ID        := qry.FieldByName('id').AsInteger;
         cls.Descricao := qry.FieldByName('descricao').AsString;
      end
      else
      begin
         cls := nil;
      end;
   finally
      qry.Free;
   end;

   Result := cls;
end;</pre>
<p>Ok, ficou bom, mas imagine a longo prazo. Para cada uma das vezes que eu precisar da classe, eu teria de criar uma nova instância de SQLQuery e configura-la. Isso pode (e quase sempre vai) me induzir a errar em algum momento, na hora que eu esquecer de passar algum parâmetro ou mesmo validar se o banco está conectado. Para evitar todos esses problemas, criaremos um Builder, que para nós será simplesmente um construtor melhor para nossa SQLQuery.</p>
<p>Esse construtor vai ser instanciado dentro do objeto de serviço que  e será vinculado à esse. Assim, todas as querys serão filhas desse objeto e serão destruídas quando esse for. Nesse builder vou precisar de duas propriedades: BancoDeDados e Transação. Assim, no construtor desse meu builder eu já as preencho e garanto que todos as querys ali criadas saem já configuradas como deve ser.</p>
<p>Desse jeito, a classe builder fica assim:</p>
<pre class="brush: delphi;">
unit unQueryBuilder;

interface

uses
  SysUtils, Classes, SqlExpr, DBXpress;

type
   TQueryBuilder = class(TObject)
   private
      FTransacao: TTransactionDesc;
      FBancoDeDados: TSQLConnection;
      procedure SetBancoDeDados(const Value: TSQLConnection);
      procedure SetTransacao(const Value: TTransactionDesc);
   public
      property BancoDeDados: TSQLConnection read FBancoDeDados write SetBancoDeDados;
      property Transacao: TTransactionDesc read FTransacao write SetTransacao;
      function NovaInstancia(Dono: TComponent): TSQLQuery;
      constructor Create(Base: TSQLConnection; Trans: TTransactionDesc);
   end;

implementation

{ TQueryBuilder }

constructor TQueryBuilder.Create(Base: TSQLConnection; Trans: TTransactionDesc);
begin
   Self.BancoDeDados := Base;
   Self.Transacao := Trans;
end;

function TQueryBuilder.NovaInstancia(Dono: TComponent): TSQLQuery;
var
   pdsNovo: TSQLQuery;
begin
   pdsNovo := TSQLQuery.Create(Dono);
   pdsNovo.Database    := Self.BancoDeDados;
   pdsNovo.Transaction := Self.Transacao;
   Result := pdsNovo;
end;

procedure TQueryBuilder.SetBancoDeDados(const Value: TSQLConnection);
begin
   FBancoDeDados := Value;
end;

procedure TQueryBuilder.SetTransacao(const Value: TTransactionDesc);
begin
   FTransacao := Value;
end;

end.</pre>
<p>Assim, toda vez que instanciar o novo serviço, devemos criar uma variável (ou propriedade) que armazene esse objeto Builder, mais ou menos assim:</p>
<pre class="brush: delphi;">   FabricaQuery := TQueryFactory.Create(Base, Trans);</pre>
<p>Refatorando a chamada da função, teremos isso:</p>
<pre class="brush: delphi;">
function TServicoMinhaClasse.getMinhaClasseById(Id: Integer): TMinhaClasse;
var
   qry: TSQLQuery;
   cls: TMinhaClasse;
begin
   qry := FabricaQuery.NovaInstancia(nil);

   try
      qry.SQL.Add('select * from tabela where id = :id');
      qry.ParamByName('id').AsInteger := Id;
      qry.Open;

      if not qry.IsEmpty then
      begin
         cls.ID        := qry.FieldByName('id').AsInteger;
         cls.Descricao := qry.FieldByName('descricao').AsString;
      end
      else
      begin
         cls := nil;
      end;
   finally
      qry.Free;
   end;

   result := cls;
end;</pre>
<p>Talvez ainda tenha muito mais a melhorar, mas já está melhor do que inicial. Embora, aparentemente, o ganho tenha sido pouco, a vantagem desse padrão só seria sentida se não o utilizássemos. As propriedades poderiam ser preenchidas incorretamente e mais validações poderiam deixar de ser executadas. Dá para aprimorar muito mais. Mas eu vou até aqui, o resto deixo com vocês.</p>
<blockquote><p>Pessoal, esse código pode gerar alguns erros. Ele foi originalmente escrito para a empresa que trabalho e por isso, muito do que era usado aqui foi substituído por componentes genéricos.</p></blockquote>
]]></content:encoded>
			<wfw:commentRss>http://julianoribeiro.com.br/blog/padrao-builder-com-delphi/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Como mudar a cor da coluna ativa da DBGrid</title>
		<link>http://julianoribeiro.com.br/blog/como-mudar-a-cor-da-coluna-ativa-da-dbgrid/</link>
		<comments>http://julianoribeiro.com.br/blog/como-mudar-a-cor-da-coluna-ativa-da-dbgrid/#comments</comments>
		<pubDate>Fri, 17 Sep 2010 22:15:02 +0000</pubDate>
		<dc:creator>Juliano Ribeiro</dc:creator>
				<category><![CDATA[Básico]]></category>
		<category><![CDATA[Delphi]]></category>
		<category><![CDATA[Desenvolvimento]]></category>
		<category><![CDATA[Canvas]]></category>
		<category><![CDATA[DBGrid]]></category>

		<guid isPermaLink="false">http://julianoribeiro.com.br/blog/?p=403</guid>
		<description><![CDATA[Eu vou começar uma série de posts, bastante básicos, sobre coisas que já usei em Delphi. A rotina abaixo deverá ser colocada no evento OnDrawDataCell, e vai mudar a cor da coluna ativa em uma DBGrid. procedure TForm1.DBGrid1DrawDataCell(Sender: TObject; const Rect: TRect; Field: TField; State: TGridDrawState); begin if gdFocused in state then with TDBGrid(sender).Canvas do [...]]]></description>
			<content:encoded><![CDATA[<p>Eu vou começar uma série de posts, bastante básicos, sobre coisas que já usei em Delphi.</p>
<p>A rotina abaixo deverá ser colocada no evento <strong>OnDrawDataCell</strong>, e vai mudar a cor da coluna ativa em uma DBGrid.</p>
<pre class="brush: delphi;">
procedure TForm1.DBGrid1DrawDataCell(Sender: TObject; const Rect: TRect; Field: TField; State: TGridDrawState);
begin
    if gdFocused in state then
        with TDBGrid(sender).Canvas do
        begin
            Brush.Color := clRed;
            FillRect( cRect );
            TextOut(Rect.Left, Rect.Top, Field.AsString);
        end;
end;
</pre>
<p>PS: Eu usei isso no Delphi 3.0, mas acho que ainda deve funcionar.</p>
]]></content:encoded>
			<wfw:commentRss>http://julianoribeiro.com.br/blog/como-mudar-a-cor-da-coluna-ativa-da-dbgrid/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Orientação à Objetos em Delphi (Parte 1 e 1/2)</title>
		<link>http://julianoribeiro.com.br/blog/orientacao-a-objetos-em-delphi-parte-1-e-12/</link>
		<comments>http://julianoribeiro.com.br/blog/orientacao-a-objetos-em-delphi-parte-1-e-12/#comments</comments>
		<pubDate>Fri, 27 Aug 2010 17:16:15 +0000</pubDate>
		<dc:creator>Juliano Ribeiro</dc:creator>
				<category><![CDATA[Artigos]]></category>
		<category><![CDATA[Delphi]]></category>
		<category><![CDATA[Desenvolvimento]]></category>
		<category><![CDATA[classe]]></category>
		<category><![CDATA[Encapsulamento]]></category>
		<category><![CDATA[OO]]></category>

		<guid isPermaLink="false">http://julianoribeiro.com.br/blog/?p=337</guid>
		<description><![CDATA[Apesar do povo no twitter querer me massacrar quando digo que o Delphi é uma linguagem (muito boa por sinal), há muito que ele não trata mais de Pascal com uma IDE bonitinha. Mas como eu respondi lá, isso é uma questão comercial, que pouco me importa, afinal, não ganho ou perco um centavo com [...]]]></description>
			<content:encoded><![CDATA[<p>Apesar do povo no twitter querer me massacrar quando digo que o Delphi é uma linguagem (muito boa por sinal), há muito que ele não trata mais de Pascal com uma IDE bonitinha. Mas como eu respondi lá, isso é uma questão comercial, que pouco me importa, afinal, não ganho ou perco um centavo com isso. Quanto a linguagem ser boa, não há dúvidas, com ela eu construi minha casa, estou pagando o carro, os meus treinamentos, a educação do meu filho&#8230;</p>
<p>Piadas à parte, vamos ao ponto, no último post que eu tratei sobre o assunto (Orientação à Objetos) a coisa ficou meio descontextualizada, principalmente por se tratar de uma palestra que fiz aqui na Produtec. Assim, vou tentar simplificar um pouco mais o conceito, sem necessariamente entrar na conversa com o banco.<br />
Primeiro vamos imaginar um problema. Alguém lhe fez a solicitação: </p>
<blockquote><p>Criar uma classe Lampada, que tenha como ser ligada, desligada e possa me responder seu atual estado (ON/OFF). Essa pessoa lhe solicitou também um formulário que interagisse com essa classe, acessando os seus métodos.</p></blockquote>
<p>Então vejamos, temos uma classe mais ou menos como a desenhada abaixo:</p>
<p><a href="http://julianoribeiro.com.br/blog/wp-content/uploads/2010/08/classe_lampada.jpg"><img src="http://julianoribeiro.com.br/blog/wp-content/uploads/2010/08/classe_lampada.jpg" alt="" title="classe_lampada" width="211" height="117" class="aligncenter size-full wp-image-340" /></a><br />
Como vemos, teremos então a classe <strong>Lampada</strong>, que possuirá um atributo privado chamado <strong>acesa</strong> do tipo <strong>boleano</strong> e três métodos públicos bastante simples; ligarLampada() muda o atributo acesa para true, desligarLampada() seta o atributo para false e isLampadaLigada() que retorna o estado do atributo. Até aqui bem simples.<br />
Para a implementação eu vou herdar de TControl, por enquanto isso será suficiente, afinal não quero ter que implementar as coisas mais básicas na mão, como a criação do componente e tal. Isso fica mais ou menos assim:</p>
<pre class="brush: delphi;">
unit uLampada;

interface

uses Controls;

type
  TLampada = class(TControl)
  private
      Facesa: Boolean;
      procedure Setacesa(const Value: Boolean);
      property acesa: Boolean read Facesa write Setacesa;
  public
      procedure LigarLampada;
      procedure DesligarLampada;
      function isLampadaLigada: Boolean;
  end;

implementation

{ TLampada }

procedure TLampada.DesligarLampada;
begin
   acesa := False;
end;

function TLampada.isLampadaLigada: Boolean;
begin
   Result := acesa;
end;

procedure TLampada.LigarLampada;
begin
   acesa := True;
end;

procedure TLampada.Setacesa(const Value: Boolean);
begin
   Facesa := Value;
end;

end.
</pre>
<p>Percebam aqui algumas particularidades do Delphi. Pra começar, os métodos tem um <em>&#8220;tipo&#8221;</em>. Métodos que necessitam retornar valores são declarados como <strong>function</strong> e os que não precisam retornar valor, portanto são somente procedimentos, são assim chamados <strong>procedure</strong>. Ambos podem receber parâmetros, mas no nosso exemplo não tivemos necessidade. A única diferença é mesmo o retorno.</p>
<p>Para declarar a propriedade <strong>acesa</strong>, eu simplesmente digitei <strong>property acesa:boolean;</strong> e pressionei o atalho <strong>Ctrl+Shift+C</strong>. Isso nos leva a outro ponto legal de destacar que é o encapsulamento. Veja como ficou o código:</p>
<pre class="brush: delphi;">
  private
      Facesa: Boolean;
      procedure Setacesa(const Value: Boolean);
      property acesa: Boolean read Facesa write Setacesa;
</pre>
<p>Assim, na prática, o valor será gravado em Facesa (o &#8220;F&#8221; é padrão do Delphi, não pergunte). Como se percebe ele completou a linha com as cláusulas read e write, determinado assim o Getter e o Setter da propriedade acesa. Portanto quando uma chamada um outro objeto acessar a propriedade acesa, a classe irá ler o valor da variável Facesa e na hora de atribuir o valor, o procedimento <strong>Setacesa(<em>const </em>Value: Boolean);</strong>.</p>
<blockquote><p>A cláusula <strong>const </strong>antes do parâmetro indica que o mesmo não pode ser alterado no corpo do procedimento. Ele pode ser atribuído normalmente na chamada.</p></blockquote>
<p>Com o procedimento SetAcesa podemos colocar quaisquer tratamentos que se fizerem necessários. Mas isso é assunto para outro post.</p>
<p>Para a aplicação rodar como pedido, devemos criar um formulário que interaja com um objeto da classe criada. Vou não criar muita firula aqui, serão apenas 3 botões, Ligar, Desligar e Status.</p>
<p><a href="http://julianoribeiro.com.br/blog/wp-content/uploads/2010/08/frmInterruptor.jpg"><img src="http://julianoribeiro.com.br/blog/wp-content/uploads/2010/08/frmInterruptor.jpg" alt="" title="frmInterruptor" width="282" height="78" class="aligncenter size-full wp-image-355" /></a></p>
<p>Aqui fica mais clara ainda a simplicidade desse sistema. Basta criar uma instância da classe TLampada e fazer com que os botões acessem os seus métodos. Veja como ficou simples.</p>
<pre class="brush: delphi;">unit uInterruptor;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, uLampada;

type
  TfrmInterruptor = class(TForm)
    btnLigar: TButton;
    btnDesligar: TButton;
    btnStatus: TButton;
    procedure btnStatusClick(Sender: TObject);
    procedure btnDesligarClick(Sender: TObject);
    procedure btnLigarClick(Sender: TObject);
    procedure FormCreate(Sender: TObject);
  private
    MinhaLampada: TLampada;
  public
  end;

var
  frmInterruptor: TfrmInterruptor;

implementation

{$R *.dfm}

procedure TfrmInterruptor.btnDesligarClick(Sender: TObject);
begin
   MinhaLampada.DesligarLampada;
end;

procedure TfrmInterruptor.btnLigarClick(Sender: TObject);
begin
   MinhaLampada.LigarLampada;
end;

procedure TfrmInterruptor.btnStatusClick(Sender: TObject);
var
   cMsg: String;
begin
   cMsg := 'A lâmpada ';

   if not MinhaLampada.isLampadaLigada then
      cMsg := cMsg + 'não ';

   cMsg := cMsg + 'está ligada.';
   ShowMessage(cMsg);
end;

procedure TfrmInterruptor.FormCreate(Sender: TObject);
begin
   MinhaLampada := TLampada.Create(Self);
end;

end.
</pre>
<p>A única dica é criar a MinhaLampada na criação do formulário. Não preciso me preocupar com dispor dela, pois ela foi criada &#8220;afiliada&#8221; ao form, portanto quando um for para o vinagre o outro vai junto.</p>
<p>Bom pessoal, agora que desaceleramos e começamos de maneira mais básica acho que consegui isolar um pouco mais os conceitos. Acredito que todos entendem que temos uma classe TLampada, com atributos privados, com métodos públicos que nos permitem controlar a lâmpada. Esclarecemos também que o que se manipula posteriormente é a instancia, o objeto MinhaLampada, não a classe. E podemos ter quantas instancias da Lampada criadas dentro da nossa aplicação.</p>
<p>No próximo post sobre o assunto vamos criar um serviço que controle a &#8220;energia&#8221; do exemplo. Até lá.</p>
]]></content:encoded>
			<wfw:commentRss>http://julianoribeiro.com.br/blog/orientacao-a-objetos-em-delphi-parte-1-e-12/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Executando scripts via Delphi</title>
		<link>http://julianoribeiro.com.br/blog/executando-scripts-via-delphi/</link>
		<comments>http://julianoribeiro.com.br/blog/executando-scripts-via-delphi/#comments</comments>
		<pubDate>Thu, 26 Aug 2010 14:24:09 +0000</pubDate>
		<dc:creator>Juliano Ribeiro</dc:creator>
				<category><![CDATA[Delphi]]></category>
		<category><![CDATA[Desenvolvimento]]></category>
		<category><![CDATA[SQL]]></category>
		<category><![CDATA[ErrorCode]]></category>
		<category><![CDATA[Interbase]]></category>
		<category><![CDATA[Oracle]]></category>
		<category><![CDATA[TMemo]]></category>
		<category><![CDATA[TSQLConnection]]></category>

		<guid isPermaLink="false">http://julianoribeiro.com.br/blog/?p=325</guid>
		<description><![CDATA[Já me ocorreu necessidade de rodar alguns scripts simples, para dar manutenção em clientes. A procedure abaixo coleta o conteúdo de um TMemo e envia para banco executar. Qualquer ErrorCode maior que zero indica que houve uma mensagem de retorno negativa. Infelizmente não tenho essa tabela de códigos disponível. procedure TForm1.ExecutaScript; var ErrorCode: Integer; begin [...]]]></description>
			<content:encoded><![CDATA[<p>Já me ocorreu necessidade de rodar alguns <strong>scripts </strong>simples, para dar manutenção em clientes. A <strong>procedure </strong>abaixo coleta o conteúdo de um <strong>TMemo </strong>e envia para banco executar. Qualquer <strong>ErrorCode </strong>maior que zero indica que houve uma mensagem de retorno negativa. Infelizmente não tenho essa tabela de códigos disponível.</p>
<pre class="brush: delphi;">
procedure TForm1.ExecutaScript;
var
  ErrorCode: Integer;
begin
   try
      ErrorCode := Conexao.ExecuteDirect(MemoSQL.Text);
      // Conexao é um TSQLConnection já conectado ao banco.

      if ErrorCode = 0 then
          ShowMessage('Script rodado com sucesso');

      {Se retornar diferente de &quot;0&quot; é porque algo de errado aconteceu}
      if ErrorCode &lt;&gt; 0 then
         raise Exception.Create( 'Error: code = ' + IntToStr( ErrorCode ) )

   except
      on E: Exception do
         ShowMessage( E.Message );
   end
end;
</pre>
<p>Só testei em <strong>Oracle</strong>, mas não vejo motivos para não rodar em <strong>Interbase</strong>.</p>
]]></content:encoded>
			<wfw:commentRss>http://julianoribeiro.com.br/blog/executando-scripts-via-delphi/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Tratando mensagem MaskEdit</title>
		<link>http://julianoribeiro.com.br/blog/tratando-mensagem-maskedit/</link>
		<comments>http://julianoribeiro.com.br/blog/tratando-mensagem-maskedit/#comments</comments>
		<pubDate>Wed, 18 Aug 2010 19:06:24 +0000</pubDate>
		<dc:creator>Juliano Ribeiro</dc:creator>
				<category><![CDATA[Delphi]]></category>
		<category><![CDATA[Desenvolvimento]]></category>
		<category><![CDATA[Máscara]]></category>
		<category><![CDATA[TMaskEdit]]></category>

		<guid isPermaLink="false">http://julianoribeiro.com.br/blog/?p=311</guid>
		<description><![CDATA[Aconteceu de eu precisar tratar uma mensagem no TMaskEdit e minha memória idosa não se lembrar de como fazê-lo. Para que isso não ocorra mais e caso alguém tenha a mesma dúvida, deixo aqui registrada a solução. Hoje, o componente em questão, estava com a máscara &#8216;!00:00:00;1;_&#8217; o que obriga o que as posições marcadas [...]]]></description>
			<content:encoded><![CDATA[<p>Aconteceu de eu precisar tratar uma mensagem no <strong>TMaskEdit </strong>e minha memória idosa não se lembrar de como fazê-lo. Para que isso não ocorra mais e caso alguém tenha a mesma dúvida, deixo aqui registrada a solução.</p>
<p>Hoje, o componente em questão, estava com a máscara<strong> &#8216;!00:00:00;1;_&#8217; </strong>o que obriga o que as posições marcadas pelo 0 sejam preenchidas. Por mais bobo que seja, basta trocar o 0 por 9 e fazer o tratamento no evento que mais lhe convier, no meu caso no <strong>OnExit </strong>do mesmo, como se segue:<br />
<span id="more-311"></span></p>
<pre class="brush: delphi;">
procedure TFrmCadFichaOper.edTempoExit(Sender: TObject);
var
tTemp: TDateTime;
begin
try
tTemp := StrToTime(edTempo.Text);
except
MsgAtencao('Formato de tempo inválido, preencha corretamente.');

if (edTempo.CanFocus) then
edTempo.SetFocus;
end;
end; </pre>
<p>No final a máscara ficou assim: <strong>&#8216;!99:99:99;1;_&#8217;</strong>.</p>
<p>Para quem riu da minha velha memória, isso eu vi em 1997 na <strong>revista Clube Delphi</strong> e vou transcrever o artigo todo aqui:</p>
<p>A propriedade EditMask é uma variável do tipo string que define a máscara que limita os dados que podem ser digitados num componente do tipo EditMask ou em um campo de um registro de um Banco de Dados. A máscara limita os caracteres considerados válidos a serem digitados pelo usuário.</p>
<p>Uma máscara consiste de três campos separados por ponto-e-vírgula. O primeiro campo é a máscara propriamente dita, o segundo campo consiste num caracter que define se os caracteres ou máscara devem ser salvos como parte dos dados. O terceiro define o caracter usado para representar os espaços em branco na máscara.</p>
<ul>
<li>! &#8211; Se um ! aparecer na máscara, caracteres em branco não são armazenados como dados.</li>
<li>&gt; &#8211; Se um &gt; aparecer na máscara, todos os caracteres seguintes estarão em letras maiúsculas, até que seja encontrado um caractere igual a &lt;.</li>
<li>&lt; &#8211; Se um &lt; aparecer na máscara, todos os caracteres seguintes estarão em letras maiúsculas, até que seja encontrado um caractere igual a &gt;.</li>
<li>&lt;&gt; &#8211; Este sinal significa que as letras maiúsculas e minúsculas serão armazenadas como digitadas pelo usuário.</li>
<li>\ &#8211; Os caracteres que seguem este sinal serão tratados como literais.</li>
<li>L &#8211; Apenas caracteres alfabéticos (a-z e A-Z) sejam aceitos nessa posição.</li>
<li>l &#8211; Apenas caracteres alfabéticos (a-z e A-Z) sejam aceitos nessa posição, mas aceita que sejam omitidos.</li>
<li>A &#8211; Apenas caracteres alfanuméricos (0-9, a-z e A-Z) sejam aceitos nessa posição.</li>
<li>a &#8211; Apenas caracteres alfanuméricos (0-9, a-z e A-Z) sejam aceitos nessa posição, mas aceita que sejam omitidos.</li>
<li>C &#8211; Este caractere faz com que quaisquer caracteres sejam aceitos nesta posição.</li>
<li>c &#8211; Este caractere faz com que quaisquer caracteres sejam aceitos nesta posição, mas aceita que sejam omitidos.</li>
<li>0 &#8211; Apenas caracteres numéricos (0-9) sejam aceitos nessa posição.</li>
<li>9 &#8211; Apenas caracteres numéricos (0-9) sejam aceitos nessa posição, mas aceita que sejam omitidos.</li>
<li># &#8211; Apenas caracteres numéricos (0-9) e sinais de mais (+) ou menos(-) sejam aceitos nessa posição, mas aceita que sejam omitidos.</li>
<li>: &#8211; Este caractere (dois pontos) é usado para separar horas, minutos e segundos em dados horários. Se outro caractere separador de horas, minutos e segundos é definido nos atributos internacionais do Painel de Controle do sistema, este caractere será usado ao invés dos dois pontos.</li>
<li>/ &#8211; É usado para separar meses, dias e anos em dados de datas. Se outro caractere separador de meses, dias e anos é definido nos atributos internacionais do Painel de Controle do sistema, este caractere será usado ao invés do caractere /.</li>
<li>; &#8211; O ponto-e-vírgula é usado para separar máscaras.</li>
<li>_ &#8211; O caractere _ insere espaços em branco na caixa de edição.</li>
</ul>
<p>Embora essa dica pareça muito boba, ajuda muito lembrar dessas coisas no momento de apuro.</p>
]]></content:encoded>
			<wfw:commentRss>http://julianoribeiro.com.br/blog/tratando-mensagem-maskedit/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Delphi orientado à objetos &#8211; parte 1</title>
		<link>http://julianoribeiro.com.br/blog/delphi-orientado-a-objetos-parte-01/</link>
		<comments>http://julianoribeiro.com.br/blog/delphi-orientado-a-objetos-parte-01/#comments</comments>
		<pubDate>Tue, 27 Jul 2010 13:47:20 +0000</pubDate>
		<dc:creator>Juliano Ribeiro</dc:creator>
				<category><![CDATA[Artigos]]></category>
		<category><![CDATA[Delphi]]></category>
		<category><![CDATA[Desenvolvimento]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[Artigo]]></category>
		<category><![CDATA[Programação]]></category>

		<guid isPermaLink="false">http://julianoribeiro.com.br/blog/?p=293</guid>
		<description><![CDATA[Já tem um bom tempo que programo com Delphi. E sempre ouvi críticas pesadíssimas sobre o quanto a linguagem é ruim. Eu sempre acreditei que existiram sempre programadores ruins e que os programas saiam ruins, o que gerou essa impressão negativa, bem como os vários problemas que a Borland (fabricante do Delphi, agora CodeGear) impôs [...]]]></description>
			<content:encoded><![CDATA[<p>Já tem um bom tempo que programo com Delphi. E sempre ouvi críticas pesadíssimas sobre o quanto a linguagem é ruim. Eu sempre acreditei que existiram sempre programadores ruins e que os programas saiam ruins, o que gerou essa impressão negativa, bem como os vários problemas que a <strong>Borland </strong>(fabricante do Delphi, agora <strong>CodeGear</strong>) impôs nas mudanças de versão. Assim, resolvi desmistificar essa coisa de que é impossível programar orientado à objetos usando o Delphi.</p>
<p>Segue o material do nosso último treinamento, sobre como usar o Delphi, orientado à objetos.<br />
Embora pareça que estamos trabalhando com OO desde sempre, afinal instanciamos objetos baseados em classes, isso não é inteiramente verdade.<br />
Como me disse um professor certa vez: <em>&#8220;Seu sistema é orientado à objetos? Ótimo. Me mostre a sua classe NotaFiscalSaída.&#8221;</em></p>
<p>Assim achei por bem usar um exemplo bem simples, estados e cidades para mostrar o poder que o Delphi tem e de quebra demonstrar que o que está errada é a maneira como programamos e não a linguagem que usamos, seja ela qual for.<br />
<span id="more-293"></span><br />
Primeiramente, começamos com alguns paralelos. No Delphi, para criarmos uma classe, precisamos cria-la como um componente, para mais tarde, criar instancias dele. Usando o <strong>Delphi 2006</strong>, eu vou em <em><strong>File > New > Package</strong></em>. Então no Project Manager eu clico sobre o pacote com o botão direito e escolho <em><strong>Add New > Other&#8230;</strong></em></p>
<p>A janela que se abrirá me dá várias opções, a que vamos usar está em<em> <strong>Delphi Projects > Delphi Files > Component</strong></em>. No Wizard seguinte escolhemos de qual componente o nosso irá herdar suas características (não vou explicar herança aqui). Nesse momento escolheremos <strong>TComponent</strong>, para pegar somente o mínimo necessário. Na próxima tela, escolha o nome do componente em C<strong>lass Name</strong>, para nós será TCidade (o &#8220;T&#8221; é padrão do Delphi, use sem questionar). Escolha a Pallete Page que deseja ou digite uma nova, lembre que esse campo é Case Sensitive, portanto atenção ao digitar. Preencha os demais campos se precisar.</p>
<p>A classe cidade:</p>
<pre class="brush: delphi;">
unit cidade;

interface

uses
  SysUtils, Classes, Estado;

type
  TCidade = class(TComponent)
  private
    Fcid_nome: string;
    Fcid_codigo: integer;
    Festado: TEstado;
    procedure Setcid_codigo(const Value: integer);
    procedure Setcid_nome(const Value: string);
    procedure Setestado(const Value: TEstado);
    { Private declarations }
  protected
    { Protected declarations }
  public
    { Public declarations }
  published
    { Published declarations }
    property cid_codigo: integer read Fcid_codigo write Setcid_codigo;
    property cid_nome: string read Fcid_nome write Setcid_nome;
    property estado: TEstado read Festado write Setestado;
  end;

procedure Register;

implementation

procedure Register;
begin
  RegisterComponents('Objetos Produtec', [TCidade]);
end;

{ TCidade }

procedure TCidade.Setcid_codigo(const Value: integer);
begin
  Fcid_codigo := Value;
end;

procedure TCidade.Setcid_nome(const Value: string);
begin
  Fcid_nome := Value;
end;

procedure TCidade.Setestado(const Value: TEstado);
begin
  Festado := Value;
end;

end.</pre>
<p>Vamos falar um pouco da classe cidade. Nela eu coloquei os principais atributos de uma cidade, somente para exemplo. Percebam que os mesmos foram criados baseado na seguinte estrutura: </p>
<pre class="brush: delphi;">
private
    Fcid_nome: string;
published
    property cid_nome: string read Fcid_nome write Setcid_nome;
</pre>
<p>(&#8230;)</p>
<pre class="brush: delphi;">
procedure TCidade.Setcid_nome(const Value: string);
begin
  Fcid_nome := Value;
end;
</pre>
<p>Traduzindo, teremos uma propriedade com o nome cid_nome, do tipo string (notem que sem tamanho definido) que lê o valor para uma variável Fcid_nome e grava através de uma procedure chamada como Setcid_nome. Ótimo, mas o que ganhamos com isso? Para que esconder o real valor de uma variável ao invés de simplesmente torná-la pública? E para que criar um procedimento para atribuir o valor, se a mudança da visibilidade já resolveria? Parece tudo uma grande perda de tempo, mas é um foco na segurança e no reuso.<br />
Imaginem que em determinado momento, nós precisaremos delimitar o tamanho da cidade para o máximo de caracteres que existem no banco de dados, que para o nosso exemplo é de 60 caracteres. Alterando o procedimento SetCid_Nome todo, eu disse TODO, o sistema passa a respeitar a nova regra, sem precisar avisar a nenhuma outra parte do sistema que isso aconteceu. Vejam como ficaria: </p>
<pre class="brush: delphi;">
procedure TCidade.Setcid_nome(const Value: string);
begin
   if Length(Value) &lt; 60 then
      Fcid_nome := Value;
end;
</pre>
<p>Viram que simples? Poderíamos melhorar ainda, criando uma mensagem de erro (exceção) que poderia ser tratada pela tela que realizou a chamada ou simplesmente exibida diretamente em tela. Algo mais ou menos assim: </p>
<pre class="brush: delphi;">
procedure TCidade.Setcid_nome(const Value: string);
begin
   if Length(Value) &lt; 60 then
      Fcid_nome := Value
   else
      raise Exception.Create('O nome da cidade não pode conter mais do que 60 caracteres.');
end;
</pre>
<p>Várias validações ou procedimentos poderiam ser feitos no momento em que a propriedade é atribuída, como preencher uma outra propriedade, carregar outros componentes em tela, enfim, o limite fica por conta da necessidade do programador.<br />
Se eu não disse antes, o nome desse método chama-se <a href="http://pt.wikipedia.org/wiki/Encapsulamento">encapsulamento</a>, pois os atributos ficam protegidos (encapsulados) em métodos que lêem e escrevem nas variáveis.<br />
Isso é meio caminho para um estereótipo usado em UML chamado JavaBean, que os meninos que mexem com Java devem conhecer bem.</p>
]]></content:encoded>
			<wfw:commentRss>http://julianoribeiro.com.br/blog/delphi-orientado-a-objetos-parte-01/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>[Delphi] Relógio usando Canvas</title>
		<link>http://julianoribeiro.com.br/blog/delphi-relogio-usando-canvas/</link>
		<comments>http://julianoribeiro.com.br/blog/delphi-relogio-usando-canvas/#comments</comments>
		<pubDate>Mon, 10 Aug 2009 11:25:44 +0000</pubDate>
		<dc:creator>Juliano Ribeiro</dc:creator>
				<category><![CDATA[Delphi]]></category>
		<category><![CDATA[Desenvolvimento]]></category>
		<category><![CDATA[Canvas]]></category>
		<category><![CDATA[Relógio]]></category>

		<guid isPermaLink="false">http://julianoribeiro.com.br/blog/?p=264</guid>
		<description><![CDATA[Segue um exemplo usado no Dojo de 06/08/2009, aqui na Produtec. Não houve tempo de concluí-lo, mas os conceitos básicos estão presentes. No código abaixo, tem somente o corpo básico, mais o ponteiro dos segundos. Fiquem à vontade para concluí-lo. Para que o exemplo funcione, basta criar um form com ClientHeight e ClientWidth de no [...]]]></description>
			<content:encoded><![CDATA[<p>Segue um exemplo usado no Dojo de 06/08/2009, aqui na <a href="http://www.produtec.com.br">Produtec</a>.</p>
<p>Não houve tempo de concluí-lo, mas os conceitos básicos estão presentes. No código abaixo, tem somente o corpo básico, mais o ponteiro dos segundos. Fiquem à vontade para concluí-lo.</p>
<p>Para que o exemplo funcione, basta criar um form com ClientHeight e ClientWidth de no mínimo 300 e neste colocar um Timer com parâmetros padrões.</p>
<pre class="brush: delphi;">
procedure TForm1.Timer1Timer(Sender: TObject);
const
   LARGURA = 300;
var
   XFinal, YFinal: Integer;
   Hora, Minuto, Segundo, MiliSegundo: Word;
   Angulo: Integer;
begin
   Refresh;
   Caption := TimeToStr(Time);  

   // Disco do Relógio
   Canvas.Pen.Width := 1;  

   Canvas.Brush.Color := clWhite;
   Canvas.Brush.Style := bsSolid;
   Canvas.Ellipse(0, 0, LARGURA, LARGURA);  

   // Ponteiros
   Canvas.Pen.Style := psSolid;
   Canvas.Pen.Width := 3;
   Canvas.Pen.Color := clBlack;  

   Canvas.MoveTo(LARGURA div 2, LARGURA div 2);  

   DecodeTime(Time, Hora, Minuto, Segundo, Milisegundo);  

   XFinal := (LARGURA div 2) + Trunc(Sin(DegToRad(180 - Segundo * 6)) * (LARGURA div 2));
   YFinal := (LARGURA div 2) + Trunc(Cos(DegToRad(180 - Segundo * 6)) * (LARGURA div 2));  

   Canvas.LineTo(XFinal, YFinal);  

end;
</pre>
<p>Dúvidas, coloquem a seguir.</p>
]]></content:encoded>
			<wfw:commentRss>http://julianoribeiro.com.br/blog/delphi-relogio-usando-canvas/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Os Turbos Chegaram!</title>
		<link>http://julianoribeiro.com.br/blog/os-turbos-chegaram/</link>
		<comments>http://julianoribeiro.com.br/blog/os-turbos-chegaram/#comments</comments>
		<pubDate>Mon, 31 Dec 2007 23:52:06 +0000</pubDate>
		<dc:creator>Juliano Ribeiro</dc:creator>
				<category><![CDATA[Delphi]]></category>

		<guid isPermaLink="false">http://julianoribeiro.com.br/blog/?p=16</guid>
		<description><![CDATA[Copiado na cara dura de Erick Sasse As versões Turbo Explorer do Delphi, Delphi .NET, C# e C++ já estão disponíveis para download gratuito. Lembre-se que estas versões são 100% gratuitas, não são trials. Podem inclusive serem utilizadas para projetos comerciais. Porém elas têm algumas limitações, sendo que a principal delas é a impossibilidade de [...]]]></description>
			<content:encoded><![CDATA[<div id="texto">
<p><span style="font-size: xx-small;"><em>Copiado na cara dura de <a href="http://www.ericksasse.com.br/">Erick Sasse</a></em></span></p>
<p>As versões Turbo Explorer do Delphi, Delphi .NET, C# e C++ já estão <a href="http://www.turboexplorer.com/downloads">disponíveis para download gratuito</a>.</p>
<p>Lembre-se que estas versões são 100% gratuitas, não são trials. Podem inclusive serem utilizadas para projetos comerciais. Porém elas têm algumas limitações, sendo que a principal delas é a impossibilidade de instalar componentes adicionais na IDE.</p>
<p>Agora só resta aguardar pela chegada das versões Pro aqui no Brasil, que serão pagas mas sem nenhuma limitação. Acredito que devem estar disponíveis mês que vem, na Borcon.</p></div>
]]></content:encoded>
			<wfw:commentRss>http://julianoribeiro.com.br/blog/os-turbos-chegaram/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

