2011-12-29 11 views
6

Estoy intentando hacer un botón que se ilumina cuando el mouse apunta sobre él. Tiene que haber un temporizador en el fondo para controlar un desvanecimiento uniforme de estos colores. No salta de un color al siguiente, gradualmente se desvanece al siguiente color.¿Cómo manipular los colores para dar un efecto brillante en tiempo real?

Ahora mi problema es que cuando vuelve a su color normal, no se fija en su color final. De hecho, sigue saltando de claro a oscuro.

Este es un botón personalizado mío, que no voy a publicar el código de, pero este código se puede colocar en cualquier cosa con un evento de entrada/salida de mouse y una propiedad de color.

Funciona estableciendo una variable FMenuDestColor. ExtractColor obtiene valores RGB basados ​​en un color. El temporizador compara cada canal RGB entre el color actual y el color de destino. Luego, el temporizador modifica el color actual para que se desvanezca al siguiente. Estos cálculos se realizan en una función llamada CalcColorFade - se ejecuta 3 veces para cada canal.

procedure ExtractColor(const Color: TColor; var R, G, B: Byte); 
begin 
    R:= GetRValue(Color); 
    G:= GetGValue(Color); 
    B:= GetBValue(Color); 
end; 

function CalcColorFade(const C1, C2: Byte): Byte; 
const 
    RGB_MULT = 1.2; 
    RGB_SENS = 5; 
begin 
    if C1 <> C2 then begin  
    if (C1 >= C2 - RGB_SENS) and (C1 <= C2 + RGB_SENS) then 
     Result:= C2 
    else 
     if C1 > C2 then 
     Result:= EnsureRange(Trunc(C1/RGB_MULT), 0, 255) 
     else 
     Result:= EnsureRange(Trunc(C1 * RGB_MULT), 0, 255); 
    end else begin 
    Result:= C2; 
    end; 
end; 

procedure TfrmMain.tmrMenuGlowTimer(Sender: TObject); 
var 
    R1, G1, B1: Byte; 
    R2, G2, B2: Byte; 
    R3, G3, B3: Byte; 
begin 
    if MenuButton.Color <> FMenuDestColor then begin 
    ExtractColor(MenuButton.Color, R1, G1, B1); 
    ExtractColor(FMenuDestColor, R2, G2, B2); 
    R3:= CalcColorFade(R1, R2); 
    G3:= CalcColorFade(G1, G2); 
    B3:= CalcColorFade(B1, B2); 
    MenuButton.Color:= RGB(R3, G3, B3); 
    end; 
end; 

procedure TfrmMain.MenuButtonMouseEnter(Sender: TObject); 
begin 
    FMenuDestColor:= clBlue; 
end; 

procedure TfrmMain.MenuButtonMouseLeave(Sender: TObject); 
begin 
    FMenuDestColor:= clNavy; 
end; 

Coloque el mouse sobre él y se desvanecerá al siguiente color. Pero saca el mouse de él, y no se bloquea en su posición en su color original: se mueve hacia adelante y hacia atrás entre la luz y la oscuridad.

Supongo que debe haber un enfoque más limpio para lograr lo que estoy haciendo, y estoy abierto a esas sugerencias también.

El intervalo del temporizador está en 70 y la constante de 1.2, cuando se cambió a 1.1, funciona bien. Entonces algo acerca de cambiarlo a 1.2 lo estropeó.

+1

Creo que encontraría su código más fácil de leer si toma el mismo código que maneja R, G y B y lo considera un procedimiento en sí mismo y lo llama tres veces: pasa 'R1' y' R2 'en la primera ejecución,' G1' y 'G2' en la segunda ejecución, etc. – sarnold

+0

@sarnold Buen consejo que habría terminado de todos modos, aunque no relacionado con la pregunta. –

+0

Cierto, por eso lo dejé como un comentario. No puedo detectar el problema que estás tratando de resolver. Simplemente dando la pista de que sería más fácil arreglarlo solo una vez que tres veces si está en esos bloques ... :) – sarnold

Respuesta

1

El problema se solucionó ajustando la otra constante RGB_SENS a 7.

Parece que cuanto más alto voy con RGB_MULT, más alto tengo que tomar RGB_SENS.

Lo que sucede es que primero obtiene el color actual del control, luego obtiene el color de destino, divide cada uno de esos colores en canales RGB, luego para cada uno de esos canales, hace esta función para obtener el "nuevo" RGB valor ...

function DoCalc(const Curr, Dest: Byte): Byte; 
const 
    RGB_MULT = 1.2; //How much color change per step 
    RGB_SENS = 10; //Distance from dest +/- until "locked" into dest 
begin 
    if Curr <> Dest then begin 
    if (Curr >= Dest - RGB_SENS) and (Curr <= Dest + RGB_SENS) then begin 
     Result:= Dest; //Lock color into destination (sensitivity) 
    end else begin 
     if Curr > Dest then begin //Needs to go down 
     Result:= EnsureRange(Trunc(Curr/RGB_MULT), 0, 255); 
     end else begin   //Needs to go up 
     Result:= EnsureRange(Trunc(Curr * RGB_MULT), 0, 255); 
     end; 
    end; 
    end else begin 
    Result:= Dest; //Just return the dest color, no change 
    end; 
end; 

Antes, RGB_MULT utilizado para fijarse en 1.1, que funcionaba bien. Pero cuando lo aumenté al 1.2, ahí fue cuando comenzó mi problema. En ese momento, RGB_SENS se estableció en 5. RGB_SENS determina qué tan lejos del color de Destino hasta que el color debe "Bloquear" en su lugar. Evidentemente, 1.2 hizo que nunca aterrizara en este rango. Después de expandir RGB_SENS a 7 (y ahora 10), funciona bien.

+0

Lo curioso es que escribí las matemáticas para esta cosa, pero no puedo explicar en palabras cómo está funcionando realmente: PI tienden a leer/hablar en lenguaje de códigos, no puedo traducir el código al inglés sencillo que bien ... –

+0

Eso es totalmente común. No trates de forzarlo en el lenguaje, a veces puede meterse con la belleza de la lógica. : P –

4

¿Por qué no simplemente cambiar al modo HSB/HSV?

Luego puede establecer su Hue (0-359) y controlar la saturación, el brillo y el alfa.

Cada uno de estos tres últimos le ofrece opciones para un efecto de brillo ondulante.

+0

Fresco, pero ¿incluye la mezcla de un color a otro, por ejemplo, de azul a verde? Mi objetivo es pasar de un color a otro, no solo un poco más claro o más oscuro. –

+0

Si rueda por el tono, los colores cambiarían pero mantendrían el brillo relativo y la saturación intactos. – sarnold

+0

Entendido, pero ¿cómo sería ir de un color a otro? Rojo a verde, azul a morado, cian a negro, blanco a azul cielo, cualquier 2 colores especificados, no veo cómo funcionaría eso. –

Cuestiones relacionadas