2

I have a "caution" image on a dialog that is shown if there are questionable parameter values. Users do not always notice it, so I want to fade it in and out cyclically over a second or so (yes, I could just toggle the Visible property, but that would look a bit like I was just toggling the Visible property). Is there a simpler way than putting it on it's own form and floating it over the dialog (and changing the AlphaBlendValue property of the form)?

Cody Gray - on strike
  • 239,200
  • 50
  • 490
  • 574
rossmcm
  • 5,493
  • 10
  • 55
  • 118

2 Answers2

8

You can do this using the Opacity parameter of TCanvas.Draw. Behind the scenes this calls TGraphic.DrawTransparent which in turn calls the Windows AlphaBlend API function. An easy way to implement this is with a TPaintBox:

procedure TAlphaBlendForm.FormCreate(Sender: TObject);
begin
  FBitmap := TBitmap.Create;
  FBitmap.Assign(Image1.Picture.Graphic);//Image1 contains a transparent PNG
  PaintBox1.Width := FBitmap.Width;
  PaintBox1.Height := FBitmap.Height;
  Timer1.Interval := 20;
end;

procedure TAlphaBlendForm.PaintBox1Paint(Sender: TObject);
begin
  PaintBox1.Canvas.Draw(0, 0, FBitmap, FOpacity);
end;

procedure TAlphaBlendForm.Timer1Timer(Sender: TObject);
begin
  FOpacity:= (FOpacity+1) mod 256;
  PaintBox1.Invalidate;
end;

If you are using an older version of Delphi without the Opacity parameter of TCanvas.Draw you can use AlphaBlend directly.

procedure TAlphaBlendForm.PaintBox1Paint(Sender: TObject);
var
  fn: TBlendFunction;
begin
  fn.BlendOp := AC_SRC_OVER;
  fn.BlendFlags := 0;
  fn.SourceConstantAlpha := FOpacity;
  fn.AlphaFormat := AC_SRC_ALPHA;
  Windows.AlphaBlend(
    PaintBox1.Canvas.Handle,
    0,
    0,
    PaintBox1.Width,
    PaintBox1.Height,
    FBitmap.Canvas.Handle,
    0,
    0,
    FBitmap.Width,
    FBitmap.Height,
    fn
  );
end;

Thanks to Giel for suggesting the Opacity parameter of TCanvas.Draw, and for Sertac for pointing out that it is quite a recent addition to TCanvas.Draw.

David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
  • That's basically the way I'd do it. Note however that TCanvas.Draw lets you pass an "opacity" parameter, so TAlphaBlendForm.PaintBox1Paint can be as simple "PaintBox1.Canvas.Draw(0, 0, FBitmap, FAlpha)" – Giel Feb 05 '11 at 13:13
  • You sure `TCanvas.Draw` has an "opacity" parameter with D2006? – Sertac Akyuz Feb 05 '11 at 15:11
  • @David - Somehow I'm getting a "The parameter is incorrect" for the `AlphaBlend` call (D2007), hope it'll work for the OP. – Sertac Akyuz Feb 05 '11 at 16:22
  • @sertac works for me fine both ways on d2010. How are you creating your bitmap? – David Heffernan Feb 05 '11 at 16:28
  • 1
    @David - The code on 'FormCreate' in the answer is in a button handler. Png image is [this](http://upload.wikimedia.org/wikipedia/commons/6/61/Icon_attention_s.png). Png support is by "PngComponents" by "Gustavo Huffenbacher Daud".. – Sertac Akyuz Feb 05 '11 at 16:44
  • @Sertac That image works fine with me. I'm guessing it's something about `TBitmap`. Is the pixel format right? Needs to be 32bpp with alpha. I suppose it could be the `pngimage` unit you are using. I think there are a couple of variants of it that existed before CodeGear expunged them. – David Heffernan Feb 05 '11 at 16:52
  • @David - Ok, need to set to `pf32bit` after the assignment to avoid 'incorrect parameter'. Still losing the alpha channel somewhere along the line. I guess you're also correct as for the rest of the comment.. – Sertac Akyuz Feb 05 '11 at 18:06
  • @Sertac Yeah, on those older Delphi's you need to work around various limitations of TBitmap, but it does seem to be better in more modern Delphi. It all just seems to work out of the box now. The alpha will likely be lost when you transfer from PNG to bitmap. I'm sure that the 'other' pngimage that I used to use with D6 handles transparency fine. – David Heffernan Feb 05 '11 at 18:11
  • Thanks for the efforts. I have posted my code (D2006) based on your comments, appended to this answer. I can see the graphic in the TPaintBox, but it is very faint, lots of flicker. The opacity is changing, but not by much, and the transparency outside the perimeter of the triangle is not working (shows as white). – rossmcm Feb 05 '11 at 22:31
  • @user this loss of transparency happens when you don't get the image into the bitmap correctly – David Heffernan Feb 05 '11 at 22:34
  • @David Hmmm not sure what I should be doing. I am loading the PNGImage at runtime with Image1.Picture.Assign (PngImageCollection1.Items [0].PNGImage). It displays with the opacity changing up to Aplha = around 30, then it seems to saturate – rossmcm Feb 05 '11 at 22:53
  • 1
    @user It's not so easy for me to help you more on this since I don't have D2006. `AlphaBlend` **is** the answer but you need to get all the pieces together. You probably need to new Q with some more details - hard to work it all it in comments! – David Heffernan Feb 05 '11 at 22:59
  • @David Done http://stackoverflow.com/questions/4910411/why-doesnt-this-d2006-code-to-fade-a-png-image-work – rossmcm Feb 06 '11 at 01:11
1

TImage does not suppor alpha transparency like you are looking for. Using a separate floating TForm is the simpliest option.

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770