26 de novembro de 2009

Delphi terá em 2010 versões para Linux e Mac OS

No evento Delphi Live! 2009 foi publicado um Roadmap listando uma série de novas funcionalidades e recursos planejados para serem incluídos em versões futuras do Delphi. Alguns dos recursos já fazem parte da versão 2010, que chegou recentemente ao mercado. Outras estão sendo anunciadas para breve, como é o caso das versões para as plataformas Linux e Mac OS - planejadas para sairem em meados de 2010. Veja abaixo a notícia que foi publicada na ComputerWorld:

O programa Delphi, ferramenta para desenvolvimento de aplicações, principalmente para PCs, ganhará no próximo ano versões para Linux e Mac OS. A informação é do vice-presidente para relacionamento com desenvolvedores da Embarcadero e evangelista da tecnologia, David Intersimone. Ele esteve esta semana no Brasil reunido com cerca de 600 desenvolvedores.

Intersimone, mas conhecido por David I, e que tem um blog no site Computerworld americana, veio ao Brasil para apresentar à comunidade que trabalha com a ferramenta de desenvolvimento as inovações incorporadas ao Delphi 2010, versão que chegou recentemente ao mercado.

O programa concorre com plataformas como .Net da Microsoft, Visual Studio e Java, passou para as mãos da norte-americana Embarcadero no meio do ano passado. Na época, a companhia comprou a divisão CodeGear da Borland, unidade responsável por ferramentas multiplataforma para bancos de dados. Entre os quais estavam o Delphi.

A Embarcadero ainda não está presente no Brasil e o atendimento aos usuários de Delphi no país continua sendo realizado pelo time da antiga Borland, comprada no ano passado pela Micro Focus.

David I diz que o Brasil tem uma comunidade atuante de Delphi e acredita que o suporte da tecnologia a outros ambientes deverá dar mais flexibilidade aos que utilizam a ferramenta para desenvolver aplicações. Até então, o programa falava somente Windows. Ele estima que a versão do produto compatível com o sistema operacional de código aberto Linux e o Mac OS da Apple deverá chegar ao mercado no meio do próximo ano.

Ao comentar sobre as novidades do Delphi 2010, o especialista destacou, que além do produto já está preparado para Windows 7, vem com interfaces baseadas no recurso touch. Essa funcionalidade vai permitir aos desenvolvedores criarem mais rapidamente aplicações interativas para serem acessadas com toque na tela para rodar em celulares, PCs, terminais bancários e em outros tipos de hardware.

David I afirma que uma das vantagens do recurso touch para os desenvolvedores e que eles vão poder levar essa funcionalidade também para as aplicações já existentes.

O Roadmap que citei no começo menciona ainda um tal Projeto Commodore, que seria a possibilidade de se compilar programas Delphi nativamente para versões 64-bits do Windows. Infelizmente, o Roadmap não estipula uma data para o lançamento dessa versão. Em outra ocasião a entrega foi prometida também para o meio de 2010 mas parece que esse não é um prazo realista.

24 de novembro de 2009

Criando Serviços do Windows - parte 2

O Delphi e o C++ Builder têm um tipo de projeto específico para a criação de Serviços do Windows. Então, o procedimento para criar uma estrutura básica de um Serviço nesses ambientes é selecionar o menu File -> New e escolher Service Application.

Um novo projeto será criado e incluirá um fonte com uma classe que representa o Serviço do Windows. A estrutura desse fonte é similar a um Data Module e permite que sejam adicionados componentes não-visuais para uso pelo Serviço - lembre-se que o serviço não tem interface gráfica e, portanto, não faz sentido admitir a inclusão de componentes visuais. O trecho abaixo reproduz a declaração inicial da classe gerada:
type
TWMyService = class(TService)
private
{ Private declarations }
public
function GetServiceController: TServiceController; override;
{ Public declarations }
end;

Veja que a base para a classe de Serviço chama-se TService. É essa classe da VCL que encapsula um Serviço e quem introduz as propriedades que devemos configurar e os eventos que teremos que responder para que o Serviço execute suas tarefas.

O passo seguinte, então, é configurar visualmente as propriedades, conforme a necessidade. Segue abaixo uma lista com as principais propriedades da classe TService e uma breve explicação de sua utilidade.
DisplayName é o nome que identificará nosso serviço no Service Control Manager (SCM), que é a parte do Windows responsável pelo gerenciamento de Serviços e que pode ser acessado através da aplicação Services existente no Painel de Controle do Windows.
ServiceType é o tipo de Serviço que se está criando. O valor padrão (e situação mais comum) é stWin32, indicando que se trata de um serviço convencional. Os outros valores permitidos transformam o Serviço num Device Driver ou File System Driver.
ServiceStartName e Password indicam o nome de usuário e senha com o qual o Serviço irá se apresentar ao Windows (quando ServiceType está configurado com stWin32. As credenciais (permissões de acesso) desse usuário é que determinarão o que o Serviço pode ou não fazer dentro do Windows. Conforme dito no post anterior, pode-se informar um dos usuários criados e mantidos pelo Windows (Local System, LocalService ou Network Service). Se for deixado em branco, o Windows assume que deve ser considerado o usuário Local System.
Dependencies lista os Serviços dos quais nosso Serviço depende. Isto é, se nosso Serviço só funcionar quando um ou mais Serviços também estiverem funcionando corretamente, os nomes desses Serviços devem ser incluídos nesta lista. O SCM, então, só poderá iniciar a execução do nosso Serviço após receber confirmação de que os Serviços dos quais ele depende estão com status ok.
StartType indica o modo de inicialização do Serviço. O valor padrão é stAuto, sinalizando que o Serviço deve ser iniciado automaticamente, junto com o Windows e sem que seja necessário um usuário se logar.
WaitHint é o tempo máximo (em milissegundos) que o SCM deve aguardar quando interagindo com o Serviço. Assim, se o tempo se esgotar o SCM interpretará que o serviço "pendurou". Caso as tarefas executadas pelo Serviço sejam demoradas, é conveniente chamar em pontos estratégicos do código a função ReportStatus da classe TService. Isso permitirá ao SCM detectar que o Serviço está ativo mas executando uma operação demorada.
A propriedade Terminated informa ao Serviço que ele deve cessar a execução. Isso pode ser devido ao fato de que alguém solicitou a interrupção do Serviço ou que o próprio Serviço detectou que sua execução não é mais necessária.

Em relação aos eventos disponíveis para a classe TService, o principal é o OnExecute. É aqui que o funcionamento do Serviço ocorre, seja através do monitoramento de eventos, seja através da publicação de meios para comunicação com outros processos (ou ambos). O evento OnExecute é disparado uma única vez e, quando ele termina sua execução, determina também o término da execução do Serviço. Juntando esse fato com o funcionamento da propriedade Terminated citada antes, a codificação do OnExecute tem, na maioria das vezes, a seguinte aparência:
procedure TWMyService.ServiceExecute(Sender: TService);
begin
while (not Terminated) do
begin
{ Processa aqui as tarefas relacionadas com o Serviço }
{ ... }

ReportStatus;
end;
end;

No caso do serviço que executa processos agendados na ABC71, esse laço dentro do evento OnExecute verifica de tempos em tempos os registros existentes no banco de dados do ERP e executa o processo numa thread separada quando é atingida a data e hora agendada para execução.

Isso levanta uma outra questão. Onde armazenar as configurações para conexão com o Banco de Dados ? É muito comum que isso seja feito através de um arquivo mas optei por armazenar tais informações no Registry do Windows, mais apropriado na minha opinião. Foi construído, então, um programa com interface gráfica que permite aos usuários configurar a conexão e monitorar a execução dos processos. Como o usuário usado pelo Serviço é diferente do usuário logado no Windows para realizar as confugurações, a gravação no Registry deve ser feita sob a chave HKEY_LOCAL_MACHINE, facilmente acessível por ambos.

23 de novembro de 2009

Criando Serviços do Windows - parte 1

Um Serviço do Windows é um tipo especial de programa projetado para executar sob demanda uma tarefa ou um conjunto de tarefas correlacionadas - o serviço fornecido. A característica mais marcante dos Serviços é o fato de que eles não possuem interface gráfica, isto é, não se espera a intervenção direta de um usuário. Por isso, o funcionamente padrão deles é ficar em execução indeterminadamente, aguardando solicitações de outros programas ou outro evento qualquer para o qual tenha sido programado.

Assim, o objetivo desse tipo de programa é fornecer um "serviço" especializado bem determinado, de modo que os outros programas podem se ater na sua própria execução e delegar ao Serviço aquelas tarefas que ele disponibiliza. Veja que essa característica torna o Serviço uma espécie de componente, capaz de atender diversos programas diferentes, mesmo que esses outros programas não tenham sido criados por você. Os programas que queiram se beneficiar do Serviço, então, terão apenas que saber como acessá-lo, isto é, qual é a sua interface. Alguns exemplos de situações onde se pode aplicar esse conceito são listados a seguir : banco de dados, Web Server, Agendador de Tarefas, Assinatura digital de documentos, etc.

De forma simplificada, podemos classificar os Serviço em duas categorias básicas, de acordo com a técnica utilizada para ativar a execução de uma tarefa. Há os que são acionados deliberadamente por outro programa e que, portanto, apenas reagem a uma solicitação, executando imediatamente a tarefa requisitada e retornando algum resultado (quando for o caso). Se encaixam nessa categoria serviços para atender ações em bancos de dados ou num Web Server ou ainda um serviço específico para assinar documentos digitalmente. A outra categoria são os Serviços que monitoram a ocorrência de um evento e executam algum processamento quando o evento é detectado. Na ABC71, por exemplo, temos um Serviço que executa processos e relatórios agendados em qualquer das estações com o Client do ERP. Ele faz isso monitorando os agendamentos registrados em uma tabela no banco de dados e executando os processos em fila quando chega a data e hora configuradas. Da forma como está exposto aqui, um mesmo serviço pode ser projetado para funcionar sem problemas até mesmo com ambas as maneiras, dependendo da situação.

Uma outra propriedade importante diz respeito à inicialização do Serviço: ele pode ser configurado para iniciar junto com o Windows, sem que seja necessário fazer login no Windows. Isso é particularmente útil quando o Serviço é instalado num servidor para atender às demandas através de uma rede, pois neste cenário o Serviço deve estar disponível independentemente se um login foi feito no Windows do servidor ou não.

Mas, se não há um login feito, quais políticas de segurança são aplicadas ao programa ? Isto é, como é determinado o que o Serviço pode ou não pode acessar ? Quais arquivos, entradas no Registry ou outro recurso qualquer do Windows ? Uma das configurações permitidas num Serviço é justamente um nome de usuário e sua senha, de modo que as permissões atribuídas a esse usuário é que determinam o que um Serviço pode ou não fazer. É permitido também escolher um dos 3 usuários padrões, criados e mantidos pelo Windows (Local System, LocalService ou Network Service), cada um com seu próprio conjunto de credenciais. Veja aqui uma explicação bem curta de cada uma dessas contas.

O Windows possui uma API própria para a criação e manipulação de Serviços. No entanto, o RAD Studio (Delphi e C++ Builder) e o Visual Studio (C#, Visual Basic) encapsulam em classes uma solução mais prática, que não exige acesso direto às APIs. Num próximo post, mostro a classe publicada no Delphi/C++ Builder e monto um exemplo simples de Serviço.

19 de novembro de 2009

Customizando a aparência de um Grid em Delphi - parte 3

Há alguns dias, tratei num post a customização da aparência de um Grid, onde mostrei alguns conceitos básicos do objeto Canvas do Delphi e C++ Builder, usado para fazer a customização num StringGrid. Os mesmos conceitos são válidos para os DBGrids mas, como há algumas diferenças, vou abordar aqui a customização desse tipo de grid.

A diferença mais importante está nos parâmetros que são passados para o evento de pintura de uma célula:
procedure TForm1.DBGrid1DrawDataCell(Sender: TObject; const Rect: TRect; Field: TField; State: TGridDrawState);

No caso do DBGrid, ao invés de nos informar a linha e a coluna que se está desenhando, o evento nos dá o campo atual da query, representado pelo parâmetro Field. Para ficar mais claro o que está acontecendo, a ordem de desenho das células é a seguinte: primeiro, um registro da query é posicionado; depois, o evento de desenho é disparado para cada uma das colunas (os campos ou Fields) selecionados na query. Novos registros são posicionados até que a parte visível do grid esteja completa ou que o fim do result set seja atingido. Com isso, cada novo registro é desenhado numa nova linha e, obviamente, cada campo ocupa uma coluna.

O trecho de código abaixo pinta o valor de um Field numérico de azul (quando positivo) ou vermelho (quando negativo).
procedure TForm1.DBGrid1DrawDataCell(Sender: TObject; const Rect: TRect; Field: TField; State: TGridDrawState);
var yCalc, xCalc : integer;
Texto : String;
lCanvas : TCanvas;
DBGrid : TDBGrid;
begin
{ Salva em variáveis locais para facilitar a clareza }
DBGrid := Sender As TDBGrid;
lCanvas := DBGrid.Canvas;

if (not (gdFixed in State) ) and
(Field.FieldName = 'VALOR')
then begin
{ Formata o valor para apresentação }
texto := FormatFloat ('###,##0.00', Field.AsFloat);

{ Cor de fundo para célula depende se está selecionada }
if gdSelected in State then
lCanvas.Brush.Color := clHighlight
else
lCanvas.Brush.Color := DBGrid.Color;

{ Cor do fonte para o campo, de acordo com o valor }
if Field.AsFloat >= 0 then
lCanvas.Font.Color := clBlue
else
lCanvas.Font.Color := clRed;

{ Preenche com a cor de fundo }
lCanvas.FillRect(Rect);

{ Calcula posição para centralizar o texto na vertical }
yCalc := lCanvas.TextHeight (texto);
yCalc := Rect.Top + (Rect.Bottom - Rect.Top - yCalc) div 2;

{ calcula posição para alinha valor numérico à direita }
xCalc := lCanvas.TextWidth (texto);
xCalc := Rect.Right - xCalc - 3;

lCanvas.TextRect (Rect, xCalc, yCalc, texto);
end
else
DBGrid.DefaultDrawDataCell (Rect, Field, State);
end;

Observe que este código precisa tratar apenas o Field que queremos - distinguido pelo nome do campo no banco de dados, ao contrário do código postado a respeito da aparência do StringGrid. Aqui, o tratamento para os demais fields e states é repassado para a função DefaultDrawDataCell do Grid, que cuida de desenhar e formatar as células que não nos interessa customizar.

E é possível determinar o número da linha atual? Há uma propriedade no DataSet chamada RecNo que indica o número sequencial do registro que está atualmente posicionado. Como o TField está associado a um DataSet (query ou table), posso usar o RecNo para, por exemplo, pintar as linhas do grid com cores alternadas, dando o efeito de zebrado:
{ Cor de fundo para as linhas }
if (Field.DataSet.RecNo mod 2) = 0 then
lCanvas.Brush.Color := clSilver
else
lCanvas.Brush.Color := DBGrid.Color;

A diferença entre os eventos OnDrawDataCell e OnDrawColumnCell é que esse segundo recebe um parâmetro com as configurações da coluna do Grid, isto é, um TColumn) ao invés do TField. Como uma das propriedades do TColumn é justamente o Field associado, adaptar o código mostrado neste post é simples. E, de acordo com o help do Delphi, é preferível usar a versão com o TColumn pois a outra é considerada obsoleta.

Embora as funções e propriedades do objeto Canvas tenha sido apresentado num contexto específico nessa série de posts sobre aparência de Grids, os conceitos podem ser usados para trabalhar em qualquer contexto onde haja um Canvas.

Mais Informações
Customizando a aparência de um Grid em Delphi - parte 1 e parte 2

15 de novembro de 2009

Google anuncia novos projetos

Parece que o pessoal do Google não consegue parar de se mexer... Além do estardalhaço que eles vêm fazendo para divulgar o Google Wave (que ainda não foi oficialmente lançado), esta semana eles fizerem mais dois anúncios relacionados a novas linhas de pesquisa em que a empresa está se envolvendo. Na verdade, o que eles anunciaram foram os primeiros resultados dessas novas linhas.

O primeiro anúncio foi que eles estão construindo uma nova linguagem de programação, chamada GO. Mas porque criar uma nova linguagem de programação se já há uma infinidade delas por aí, com os mais variados propósitos e uma vasta gama de características diferentes ?

A proposta, segundo o site oficial do GO, é resolver duas frustrações que os desenvolvedores da linguagem têm. Para eles, as linguagens existentes hoje cujo código resulta em programas com melhor performance - como C/C++ - têm um processo de compilação bastante lento. Dentre as razões alegadas para essa lentidão, eles citam a existência de arquivos header que contêm as pré definições necessárias para se usar funções e classes num programa e a tipologia de dados do C/C++. Ambas as questões são resolvidas, com a eliminação das pré definições e com a introdução de tipos de dados dinâmicos, no mesmo estilo dos tipos existentes no JavaScript. Para finalizar, a nova linguagem não possui a ideia de ponteiros no sentido entendido pelo C/C++ e outras, o que permitiu também a criação de um garbage collector mais eficiente. Isto é, o gerenciamento da memória do GO é automatizado como no Java e no .NET.

A outra frustração que a linguagem procura resolver é o fato de que o hardware dos computadores tem evoluido muito, em especial em relação ao número de processadores, enquanto as linguagens de programação não têm acompanhado tal evolução. Neste sentido, a sintaxe do GO procura facilitar a criação de programas que tirem o máximo desse tipo de arquitetura, de modo que o resultado são programas pequenos e leves com capacidade de trocar informações entre si e sincronizar suas execuções de forma nativa, isto é, tudo contemplado na própria sintaxe da linguagem.

Embora os engenheiros do Google estejam usando internamente esta ferramenta, o site do GO alerta que ela ainda não é madura o suficiente pra uso em projetos comerciais e que a divulgação da linguagem neste ponto tem justamente o objetivo de obter sugestões da comunidade de desenvolvedores para complementá-la e testá-la.

A segunda linha de pesquisas que eles revelaram diz respeito à comunicação entre os navegadores de internet (os browsers) e os servidores da Internet. O mecanismo existente hoje é o protocolo HTTP, estabelecido como padrão nos primórdios da internet comercial. A pesquisa do Google tenta minimizar alguns gargalos decorrentes da forma como esse protocolo permite a um navegador de internet receber certos tipos de informação do servidor Web e como o servidor as disponibiliza. São recursos como streams de áudio e vídeo e a compactação de dados de controle do HTTP, além do modo como o servidor prioriza as requisições feitas pelo navegador.

O novo protocolo foi chamado de SPDY (speedy) e, segundo o blog dos pesquisadores, os testes preliminares em laboratório foram animadores, resultando em cargas de páginas até 55% mais rápidas. Para o teste, foi usado um servidor de Web criado para se comunicar usando o SPDY e uma versão modificada do Chome, compatibilizado para entender o novo protocolo. Novamente, a pesquisa ainda não gerou um produto e a fase atual do desenho no novo protocolo é de abertura para que a comunidade de desenvolvedores possa conhecê-lo e dar sugestões para melhorá-lo.

Veja neste link a notícia publicada no site IDG Now! sobre o SPDY.

10 de novembro de 2009

Customizando a aparência de um Grid em Delphi - parte 2

Continuando o post anterior, sobre como customizar a aparência de grids em Delphi, mostro aqui exemplos práticos dessa customização.

Os parâmetros aceitos pelo evento OnDrawCell num StringGrid são mostrados abaixo.
procedure TForm1.StringGrid1DrawCell(Sender: TObject; ACol, ARow: Integer; Rect: TRect; State: TGridDrawState);

Este evento é disparado uma vez para cada célula do Grid que precisar ser desenhada. Além do tradicional Sender (que representa o próprio grid que está gerando o evento), o evento também trás a linha e coluna que identifica qual é a célula desenhada. O parâmetro Rect indica um retângulo dentro do Canvas cujas coordenadas delimitam a célula a ser desenhada, isto é, é o espaço do Canvas reservado para o desenho da Célula indica pelos parâmetros ACol, ARow. O último parâmetro - State - é um conjunto de indicadores que sinalizam condições especiais para o desenho da célula. São estados tais como se a célula está selecionada ou não, se está com o foco para entrada de dados e se está numa das linhas ou colunas fixas do Grid.

Antes de prosseguir com a inclusão de código como resposta a esse evento, vou modificar a propriedade DefaultDrawing do StringGrid para False. Isso avisa a VCL que nós estamos assumindo o controle do desenho das células e que a VCL não deve executar as suas rotinas internas associadas à exibição dos dados de cada célula. Isto dito, segue um exemplo de resposta padrão para modificar as cores apresentadas no texto de um stringGrid:
procedure TForm1.StringGrid1DrawCell(Sender: TObject; ACol, ARow: Integer;
Rect: TRect; State: TGridDrawState);
var yCalc : integer;
Texto : String;
lCanvas : TCanvas;
begin
{ Salva em variáveis locais por questão de clareza do código }
texto := StringGrid1.Cells[ACol, ARow];
lCanvas := StringGrid1.Canvas;

if gdFixed in State then begin
{ Cor do fonte e de fundo para linhas e colunas fixas }
lCanvas.Font.Color := clBlack;
lCanvas.Brush.Color := StringGrid1.FixedColor;
end else
if gdSelected in State then begin
{ Cor do fonte e de fundo para linhas e colunas selecionadas }
lCanvas.Font.Color := clWhite;
lCanvas.Brush.Color := clHighlight;
end
else begin
{ Cor do fonte e de fundo para linhas e colunas com dados }
if ACol mod 2 = 0 then
lCanvas.Font.Color := clBlue { azul nas colunas pares}
else
lCanvas.Font.Color := clRed; { vermelho nas ímpares }
lCanvas.Brush.Color := StringGrid1.Color;
end;

{ Preenche com a cor de fundo }
lCanvas.FillRect(Rect);

{ Calcula posição para centralizar o texto na vertical }
yCalc := lCanvas.TextHeight (texto);
yCalc := Rect.Top + (Rect.Bottom - Rect.Top - yCalc) div 2;
lCanvas.TextRect (Rect, Rect.Left + 3, yCalc, texto);
end;

Seguem algumas considerações sobre o trecho acima. A primeira coisa a observar é que grande parte do código é dedicada a configurar as propriedades do Canvas - o Brush para pintar a cor de fundo da célula e a Font para determinar a cor do texto. Algumas dessas configurações consideram o "Estado" da célula, isto é, se ela está selecionada ou se é parte da linha e coluna fixa. Poderia ainda ter levado em consideração também qual é a célula que está com foco e dar-lhe algum destaque.

O outro objeto disponível (Pen) não é alterado neste exemplo mas poderia ter sido caso quiséssemos desenhar linhas com características distintas. Isso inclui a borda da célula. Repare apenas que o Rect passado no parâmetro não considera a borda da célula, de modo que teríamos que expandir manualmente este retângulo caso quiséssemos aplicar uma cor ou espessura diferente à borda.

Uma coisa importante a ressaltar é que o Grid em si possui uma propriedade Font cuja configuração é usada como padrão para desenhar os textos, ou seja, o que configuramos nela é repassado para o Canvas antes da pintura do Grid iniciar. Modificar a Font do Grid, então, dispara a pintura do componente como um todo - e não de uma célula específica. Por isso, alteramos diretamente a fonte do Canvas no evento de pintura da célula, evitando que novos eventos de pintura sejam gerados eternamente.

No exemplo, as colunas pares são escritas em azul e as ímpares em vermelho. Claro que faria mais sentido interpretar o texto da célula e aplicar-lher cores mais adequadamente.

A linha de código lCanvas.FillRect(Rect) usa as configurações feitas no Brush para pintar o fundo da célula antes de aplicarmos o texto associado a ela. O comando lCanvas.TextRect (Rect, Rect.Left + 3, yCalc, texto) usa as configurações de fonte do Canvas para desenhar o texto da célula centralizado na vertical em relação ao retângulo reservado para a célula.

5 de novembro de 2009

Customizando a aparência de um Grid em Delphi - parte 1

As tabelas - ou grids - são um recurso bastante usado em aplicações Delphi, principalmente aquelas que implementam acesso a informações em bancos de dados e que, portanto, fazem uso dos grids para tabular registros do banco de dados. O funcionamento padrão dos Grids em Delphi dão conta de exibir corretamente as informações associadas a eles, sem precisar de muito configuração. No geral, basta alimentar as células internas (no TStringGrid) ou ajustar as fontes de dados e queries (no TDBGrid) para ter um Grid funcional, exibindo seu conteúdo em linhas e colunas e permitindo navegação.

Há situações, no entanto, que o funcionamento básico não é o bastante. Um dos módulos disponíveis no ERP da ABC71, por exemplo, é um MRP II que faz uso intensivo de grids para exibir informações relacionadas ao Planejamento de Produção. Nestes grids é necessário dar destaque a células cujo conteúdo exija uma atenção diferenciada - falta de saldo de um produto, por exemplo. Uma outra situação, esta mais convencional, seria mostrar créditos em azul e débitos em vermelho num grid com dados do Balanço.

Há um evento nos grids com o nome de OnDrawCell (ou OnDrawDataCell, no DBGrid) e que foi projetado justamente para permitir a customização da aparência desses grids.

Antes de seguir falando sobre o evento em si, é necessário introduzir um conceito indispensável para podermos codificar a nova aparência. Em Delphi e C++ Builder, todos os componentes visuais (aqueles que aparecem na tela quando o programa é executado) são construídos em cima de uma tela de pintura chamada Canvas. Um Canvas é uma matriz de pontos - os pixels - que cobre toda a altura e largura reservada para o componente. Cada ponto tem sua própria cor, de modo que podemos dar ao componente a aparência que quisermos apenas preenchendo os pontos de acordo com o desejado.

No Delphi e no C++ Builder, os Canvas são instâncias da classe TCanvas, que na verdade encapsulam chamadas a uma biblioteca da API do Windows denominada GDI+. O GDI+ é a responsável pelos gráficos do Windows, incluindo o desenho de textos, linhas e imagens além de transmitir corretamente esses gráficos para a mídia a que se destinam (a tela do computador ou o papel numa impressora, por exemplo).

O TCanvas disponibiliza funções para desenho de linhas e polígonos, preenchimento de áreas com cores e padrões, desenho de textos e renderização de imagens já prontas. As principais propriedades do TCanvas e a utilidade de cada uma é descrita na lista abaixo:
Brush: O Pincel é usado para configurar cores e padrões de preenchimento de áreas. Os padrões permitidos incluem alguns valores predefinidos e a possibilidade de espeficar um Bitmap como modelo. Funções do TCanvas que desenham a cor de fundo (como o Rectangle, que é um retângulo preenchido) também usam as propriedades definidas no Brush para fazerem o preenchimento.
Pen: A Caneta define como será feito o desenho de linhas, incluindo a cor dos pontos que a comporão, a largura da linha e um padrão de desenho (linha cheia, pontos, traços, etc.). As funções que desenham polígonos também usam a configuração do Pen para traçar as linhas que limitam o polígono (como no caso do Rectangle)
Font: A Fonte permite estabelecer as características dos textos que serão desenhados, incluindo a família da fonte (Arial, Courier, etc.), o tamanho e cor das letras, se terá alguma decoração extra (negrito, itálico, etc.). Usada pelas funções relativas ao desenho de textos como TextOut.
CopyMode: Essa propriedade é usada quando se faz cópia de partes (ou o todo) de um Canvas para outro. Ela afeta o modo como essa cópia é feita, determinando o tipo de combinação entre os pontos existentes em cada Canvas. Isto é, se as cores dos pontos no Canvas de origem apenas substituirão aqueles existentes no destino ou se será aplicado algum operador lógico ou uma outra regra de combinação. Como resultado, pode-se conseguir uma série de efeitos.
Pixels: Cada um dos pontos que compõem a tela de pintura pode ser acessado individualmente através dessa propriedade. Ela é um array bidimensional (largura e altura da área de pintura) que permite mudar a cor mantida em cada ponto. Usar a propriedade Pixels é útil quando se quer traçar os pontos determinados por uma função matemática - algo como y = f(x).

Consulte a documentação do TCanvas para maiores detalhes sobre essas propriedades e as funções existentes.

No próximo post, volto com o exemplo dos Grids customizados para mostrar na prática o uso do Canvas.

Mais Informações
Documentação do GDI+

1 de novembro de 2009

Incluindo mapas em um Web site

Parece que virou mania trabalhar com mapas para facilitar a visualização de locais, para dar instruções de como chegar a um determinado local ou apenas para visitar vitualmente pontos turísticos como diversão. São ferramentas para o computador como o Google Earth ou aparelhos que você pode carregar consigo, como GPSs ou celulares. Na internet, endereços como o Apontador permitem que você estabeleça rotas para ir de um ponto a outro.

A sofisticação dessas ferramentas tem aumentado cada vez mais, com exibição de imagens de satélite em melhor resolução e inclusão de outros serviços associados, como indicação de ônibus que passam pelo local ou próximo a ele, estações de metrô nas proximidades, lojas e caixas 24 horas localizadas nas redondezas, etc.

Agora, também está ficando mais fácil incluir este tipo de serviço no seu próprio site. Como parte do sistema de buscas Bing, a Microsoft lançou um conjunto de serviços e APIs que permitem formatar um mapa com as características desejadas e incluí-lo no seu site.

De acordo com o site da Microsoft, "o Bing Maps é um serviço online de mapas que permite aos usuários pesquisar, descobrir, explorar, planejar e compartilhar informações a respeito de locais específicos. Ao usar mapas tradicionais de rodovias, fotos aéreas com textos, fotos em ângulo baixo aéreas e de alta resolução e capacidade de pesquisa por aproximação, o Bing Maps fornece oportunidades únicas aos desenvolvedores de software para incorporar tanto localizações fixas quanto busca por locais específicos em suas aplicações Web".

A API é disponibilizada como um conjunto de classes JavaScript, apropriadas para inclusão numa página HTML. Para usá-la, então, precisamos incluir no cabeçalho do HTML uma referência a essas classes JavaScript:
<script type="text/javascript" src="http://ecn.dev.virtualearth.net/mapcontrol/mapcontrol.ashx?v=6.2"></script>

A classe principal dessa API é a VEMap, provendo acesso aos mapas em si e introduzindo funções para dar-lhes a aparência desejada, traçar rotas, incluir marcações customizadas, etc.. O funcionamento básico dela está exemplificado na função abaixo, extraído do mapa que é exibido mais em baixo nesse post:
function GetMap()
{
map = new VEMap('myMap');
map.LoadMap(new VELatLong(-23.5656,-46.6524),16,'h' ,false);
}

A função LoadMap aceita como parâmetro um par Latitude/Longitude com as coordenadas do ponto que será exibido no mapa. Os demais parâmetros indicam, na sequência, a profundidade do zoom aplicado (de 1 para o mais afastado até 20 para maior aproximação), o tipo de imagem será apresentada (imagens de satélite, mapa tradicional ou um híbrido desses dois) e, por último, se o mapa permanecerá fixo na posição configurada (true) ou se permitirá interação com o usuário (false).

O nome 'myMap', informado como parâmetro ao construtor da VEMap, é o ID da tag HTML onde o mapa será desenhado. No exemplo abaixo, a função GetMap escrita no quadro anterior é chamada no evento OnLoad da página. Veja que há uma tag DIV cujo ID é 'myMap' - é dentro desta tag que o mapa será apresentado.
<body onload="GetMap();">
<div id='myMap' style="position:relative;height:400px;"></div>
</body>

O resultado é o mapa abaixo. Ele está permitindo interação, isto é, você pode navegar para outros pontos e modificar a forma de exibição.

Se não conseguir visualizar o mapa acima, clique aqui. Se você usa o Firefox com o complemento NoScript, terá que liberar a execução de scripts para o endereço onde o Bing armazena os scripts do programa de Mapas antes de poder visualizar o mapa publicado aqui.

Além do código básico mostrado aqui, o mapa reproduzido acrescenta uma marcação indicando a localização exibida - no caso, o endereço da ABC71 em São Paulo. Outros recursos disponíveis mas não representados no exemplo são a capacidade de traçar uma rota entre dois pontos, encontrar pontos de referência e endereços, visão 3D e "Birds Eye" (um plano inclinado em relação ao chão ao invés de paralelo ao chão), etc.

Uma ferramenta que a Microsoft disponibilizou junto com o SDK facilita bastante a criação do código HTML envolvido na publicação de mapas. Trata-se do Bing Maps Interactive SDK que apresenta num menu a lista de recursos disponíveis na ferramenta e um painel lateral com o mapa gerado pela opção selecionada. Quando você terminar de montar o mapa com as características que você quer, basta mudar para a guia Source Code e copiar o código HTML gerado com o exemplo para incluí-lo em seu site.