Caixa de diálogo
Como criar uma caixa de opções um diferente do padrão

Não gosto deste nome, mas que se há de fazer... Você pode estar se perguntando "se já existem componentes prontos, por que se dar ao trabalho?". Por duas razões fundamentais: primeiro não somos obrigados a aceitar todas as soluções impostas pelos grandes (nem sempre elas são as melhores); segundo porque assim procedendo podemos organizar melhor nossos projetos. Além disso, os programas passam a ter uma "personalidade" própria.

Criei um pequeno sistema que uso para montar seletores independentes (prefiro chamá-los assim), baseado em alguns conceitos tratados aqui mesmo, no club TILT, na matéria sobre figuras elásticas. Alí mostrei como "arrastar" alças de uma TImage. Agora vamos arrastar uma "caixa" inteira.

Nosso seletor é baseado no objeto TPanel por uma razão especial: tudo o que é criado "dentro" dele, a ele pertence e o acompanha automaticamente. Quer dizer, quando o TPanel fica invisível, todos os objetos criados nele tornam-se invisíveis também.

Claro, vamos configurar nosso seletor com uma barra de título e um botão de encerramento. O deslocamento do seletor ser dará ao arrastarmos a barra (aqui chamada de BarCor). Veja a figura abaixo:

Este é o nosso seletor, que no caso será um seletor para cores. Ao retornar, as variáveis globais Paper e Ink conterão as seleções realizadas pelo usuário. Vamos ver isso depois, agora vamos nos concentrar no deslocamento do TPanel (que chamaremos de PanCor).

Tudo é feito mediante o uso de três variáveis (podem ser variáveis globais e, se tivermos outros seletores sem nosso programa, seu uso poderá ser compartilhado). São elas:

  var 
    Lx,Ly: word;
    Lk: byte;

Lx e Ly conterão as coordenadas da posição do mouse, dentro de BarCor. Assim poderemos "mapear" os deslocamentos do cursor. Ligamos o arrasto ao pressionar o botão esquerdo do mouse sobre a barra de título (BarCor). O evento usado é BarCorMouseDown.

  begin
    Lx:= X; Ly:= Y; Lk:= 1;
  end;

Lk sendo igual a 1, indicará para a rotina que criaremos no evento BarCorMouseMove que o mouse está sendo movido com o botão pressionado (arrastamento). Veja como fica esse evento:

  begin
    if Lk = 1 then begin
      if X > Lx then PanCor.Left:= PanCor.Left + (X - Lx);
      if X < Lx then PanCor.Left:= PanCor.Left - (Lx - X);
      if Y > Ly then PanCor.Top:= PanCor.Top + (Y - Ly);
      if Y < Ly then PanCor.Top:= PanCor.Top - (Ly - Y);
    end;
  end;

Assim, PanCor é deslocada na mesma proporção que o movimento do mouse. Como todos os objetos de PanCor se movem também, o cursor estará sempre dentro da área da barra de título e portanto monitorará o movimento não importando para onde levemos o rato.

Para desligar o deslocamento, ao soltar o botão do mouse basta "desligar" a variável Lk (evento BarCorMouseUp):

  begin
    Lk:= 0;
  end;

Moleza, não é mesmo? Então vamos ver agora um outro detalhe: como lidar com cores. Sabemos que as cores no Windows são tratadas em seu formato True Color, ou seja, com todas as componente RGB convertidas para um único valor do tipo longint.

A faixa válida para esse tipo de variável vai de -2.147.483.648 a +2.147.483.647. Bonito de se ver, mas totalmente impraticável para lidarmos com cores. Senão vejamos: a cor branca possui o valor 16.777.215 e o preto possui o valor 0. Todas as outras 16 milhões de tonalidades então nesta faixa. Como identificar cada uma delas?

Simples: cada cor é composta por três valores que variam de 0 a 255. A variável longint possui quatro bytes de tamanho. Os três primeiros bytes indicam contém esses valores. Se convertermos a cor branca para a hexadecimal, teremos: 00FFFFFF, ou seja 00 FF FF FF onde cada FF corresponde ao valor máximo 255 de cada componente (RGB).

Assim, para calcular o valor de uma cor, partindo dos valores dos seus componentes individuais, basta multiplicar Blue por 65536, Green por 256 e somar Red (lembre-se que em informatiquês o primeiro byte é o byte mais à direita e portanto o R é o byte de menor ordem).

Veja a procedure que transforma as três componentes em um valor longint (Ink);

  procedure CodeCor;
  begin
    Ink:= (Blue * 65536) + (Green * 256) + Red;
    if Ink < 0 then Ink:= Ink and $00FFFFFF;
  end;

A segunda linha é para desencargo de consciência. Se acontecer, por alguma razão qualquer, um estouro ou um valor inadequado, a variável Ink será imediatamente recolocada dentro da sua faixa válida de cores.

Para decodificar um valor longint nas três componentes individuais:

  procedure DecodeCor;
  begin
    Red:= Ink and $000000FF;
    Green:= 0;
    if (Ink and $0000FF00) <> 0 then 
       Green:= (Ink and $0000FF00) div 256;
    Blue:= 0;
    if (Ink and $00FF0000) <> 0 then 
       Blue:= (Ink and $00FF0000) div 65536;
  end;

Aqui as duas linhas "if" existem para proteger de uma divisão por zero, o que daria um tremendo problema para o processador.

Bem, é isso aí. Os demais objetos e componentes não possuem nada de excepcional. Basta uma olhada com atenção no fonte que você compreenderá a mecânica da coisa toda. Mas, tendo alguma dúvida, o botão de e-mail está ao alcance do cursor do mouse.

Gostou? Clique no link abaixo para baixar o fonte completo desta matéria.


Download...
Clique no link para fazer o download dos arquivos. Se sua assinatura do club TILT está para vencer, clique aqui e saiba como renová-la.

Fontes completos do exemplo da matéria
 
online