controles gradientes ou transparentes usando canvas

12/12/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!


Vitor^_^

Respostas

12/12/2005

Ipc$

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.


Responder Citar

12/12/2005

Vitor^_^

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:


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!


Responder Citar

12/12/2005

Ipc$

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.
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.


Responder Citar

13/12/2005

Fx|hand

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:

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&93;);
    {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&91;index&93;);
    {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 !


Responder Citar

13/12/2005

Adriano Santos

[quote:24cd0c1960=´FX|HanD´]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:

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&93;);
    {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&91;index&93;);
    {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 ![/quote:24cd0c1960]

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


Responder Citar

13/12/2005

Vitor^_^

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:
ListBox1.Canvas.TextOut(Rect.Left + 20,Rect.Top + 3,ListBox1.Items[index&93;);


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

Valew!


Responder Citar