Array
(
)

controles gradientes ou transparentes usando canvas

Vitor^_^
   - 12 dez 2005

Gostaria de saber como posso fazer para tornar um listbox ou qualquer controle semelhante transparente ou gradiente, mas de modo que os itens continuem aparecendo.

fiz uma procedure pra deixar o listbox gradiente, mas o canvas é pintado ´por cima´ dos itens e, ao selecionar um item, a cor de fundo do listbox volta ao normal.

Grato!


Ipc$
   - 12 dez 2005

Se vc pinta pelo Canvas, vc deve pintar os ítens também.
Para não voltar à cor original, defina uma WindowProc para o ListBox e coloque a rotina do Canvas neste método. Não esqueça de voltar a WindowProc original no onDestroy.


Vitor^_^
   - 12 dez 2005

oops:

1)O que é uma windowproc e como eu faço uma?
2)se eu pintar cada um dos itens com um gradiente, vai ficar um gradiente em cada item ou um gradiente no listbox inteiro?
3) seria mais fácil eu deixá-lo transparente? a form em que ele está já tem o gradiente.

o procedure que eu usei foi essa, copiada do site delphiabout:


#Código

procedure TfrmMediaplayer.GradientControl(controle: TListBox; startcolor, endcolor: TColor);
// Horizontal gradient fill of form background
var
startr: integer;
startg: integer;
startb: integer;
endr: integer;
endg: integer;
endb: integer;
curr: integer;
curg: integer;
curb: integer;
i: integer;
r: TRect;
nolines: byte;
curpct: integer;
bitspix: longint; // bits per pixel
begin
// Convert TColor to RGB
startr := startcolor and $000000FF;
startg := (startcolor and $0000FF00) div 256;
startb := (startcolor and $00FF0000) div 256 div 256;
endr := endcolor and $000000FF;
endg := (endcolor and $0000FF00) div 256;
endb := (endcolor and $00FF0000) div 256 div 256;

// Calc no of rectangles (lines) with different colors
if controle.Height < 250 then
nolines := controle.Height
else
nolines := 250; // max 250 different rectangles (no more needed)
bitspix := GetDeviceCaps(controle.Canvas.Handle, BITSPIXEL); // Get bits per pixel
if (bitspix = 8) and (nolines > 50) then // 256 colors
nolines := 50
else if bitspix < 8 then // less than 256 colors
nolines := 4; // poor guy

r.Left := 0; // Left of rectangle
r.Right := controle.Width; // Right of rectangle

for i := 0 to nolines do // draw gradient
begin

curpct := (i * 100) div nolines; // ¬ change (gradient)

// calc red for current rectangle
if startr > endr then
curr := startr - (curpct * (startr - endr) div 100)
else
curr := startr + (curpct * (endr - startr) div 100);

// calc green for current rectangle
if startg > endg then
curg := startg - (curpct * (startg - endg) div 100)
else
curg := startg + (curpct * (endg - startg) div 100);

// calc blue for current rectangle
if startb > endb then
curb := startb - (curpct * (startb - endb) div 100)
else
curb := startb + (curpct * (endb - startb) div 100);

// set draw color for current rectangle
controle.Canvas.Brush.Color := RGB(curr, curg, curb);

// calc rectangle top/bottom
r.Top := i + (i * (controle.Height div nolines));
r.Bottom := r.Top + (controle.Height div nolines) + 1;

// draw rectangle on canvas
controle.Canvas.FillRect(r);
end;
end; // GradientForm


valew!


Ipc$
   - 12 dez 2005

1 - WindowProc é um método interno de cada TControl que recebe todas as msgs enviadas para ele. Então quando o controle volta à sua cor original após vc aplicar o Canvas, ele recebe uma msg e nela vc aplica o Canvas novamente.#Código

procedure TForm1.FormCreate(Sender: TObject);
var wOri:TWndMethod;
begin
wOri := ListBox1.WindowProc; // aqui vc salva e no onDestroy vc restaura
ListBox1.WindowProc := WP; // aqui vc diz que todas as msgs vão para WP
end;
procedure TForm1.WP(var Msg:TMessage);
begin
// aqui vc aplica o Canvas
end;

2 - O FillRect preenche o espaço de TRect com a cor de Brush.Color, depois vc deve reescrever o texto dos ítens pelo TextRect ou TextOut; vc pode modificar a Font.Color também.
3 - Se puder ficar transparente, acho que daria menos trabalho.


Fx|hand
   - 13 dez 2005

naum é mais facil usar o evento OnDrawItem do ListBox ?!?!?

eu fiz um exemplo aki utilizando esse evento e funcionou na boua...
só naum deixei gradienti pq é mto trampo... mais saca só !

Adicione um listbox no seu Form, depois mude a propriedade Style pra lbOwnerDrawVariable, depois vá ao evento OnDrawItem e adicione esse codigo:

#Código


procedure TForm1.ListBox1DrawItem(Control: TWinControl; Index: Integer;
Rect: TRect; State: TOwnerDrawState);
begin
if Rect.Top < HeaderControl1.Height then exit;
if Rect.Top > ListBox1.Height then exit;
if OdSelected in state then begin
{draw background}
ListBox1.Canvas.Brush.Style := bsSolid;
ListBox1.Canvas.Brush.Color := clInactiveCaptionText;
ListBox1.Canvas.FillRect(Rect);
{draw background}
{Draw Text}
ListBox1.Canvas.Font.Color := clBlack;
ListBox1.Canvas.TextOut(Rect.Left + 20,Rect.Top + 3,ListBox1.Items[index]);
{Draw Text}
end else begin
{draw background}
ListBox1.Canvas.Brush.Style := bsClear;
ListBox1.Canvas.Brush.Color := clWhite;
ListBox1.Canvas.FillRect(Rect);
{draw background}
{Draw Text}
ListBox1.Canvas.Font.Color := clBlack;
ListBox1.Canvas.TextOut(Rect.Left + 20,Rect.Top + 3,ListBox1.Items[index]);
{Draw Text}
end;
end;


pro q eu keria funcionou legal... e eu fiz umas coisas a mais ainda, colokei uma imagem no espaço em branco antis do texto... mais ai é so vc pensar um poko q fica facil !


Adriano Santos
   - 13 dez 2005


Citação:
naum é mais facil usar o evento OnDrawItem do ListBox ?!?!?

eu fiz um exemplo aki utilizando esse evento e funcionou na boua...
só naum deixei gradienti pq é mto trampo... mais saca só !

Adicione um listbox no seu Form, depois mude a propriedade Style pra lbOwnerDrawVariable, depois vá ao evento OnDrawItem e adicione esse codigo:

#Código


procedure TForm1.ListBox1DrawItem(Control: TWinControl; Index: Integer;
Rect: TRect; State: TOwnerDrawState);
begin
if Rect.Top < HeaderControl1.Height then exit;
if Rect.Top > ListBox1.Height then exit;
if OdSelected in state then begin
{draw background}
ListBox1.Canvas.Brush.Style := bsSolid;
ListBox1.Canvas.Brush.Color := clInactiveCaptionText;
ListBox1.Canvas.FillRect(Rect);
{draw background}
{Draw Text}
ListBox1.Canvas.Font.Color := clBlack;
ListBox1.Canvas.TextOut(Rect.Left + 20,Rect.Top + 3,ListBox1.Items[index]);
{Draw Text}
end else begin
{draw background}
ListBox1.Canvas.Brush.Style := bsClear;
ListBox1.Canvas.Brush.Color := clWhite;
ListBox1.Canvas.FillRect(Rect);
{draw background}
{Draw Text}
ListBox1.Canvas.Font.Color := clBlack;
ListBox1.Canvas.TextOut(Rect.Left + 20,Rect.Top + 3,ListBox1.Items[index]);
{Draw Text}
end;
end;


pro q eu keria funcionou legal... e eu fiz umas coisas a mais ainda, colokei uma imagem no espaço em branco antis do texto... mais ai é so vc pensar um poko q fica facil !

Eu fiz o teste aqui com o Gradiente e nao funcionou do jeito que o victor^_^ quer.


Vitor^_^
   - 13 dez 2005

Eu fiz isso que você falou e ficou legal, deu um efeito da hora, mas não consegui juntar isso com o gradiente. Tem como deixar listbox com fundo transparente e o texto dos itns aparecendo normalmente?

outra coisa, eu não entendi essa parte do código:
#Código

ListBox1.Canvas.TextOut(Rect.Left + 20,Rect.Top + 3,ListBox1.Items[index]);


porque você soma 3 no top? isso deixa meio deslocado pra baixo a seleção. Eu não somei com nada essa parte.

Valew!