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.