I am customizing OnDrawItem event to draw icons next to item names. Here is my code so far for the event OnDrawItem:
void __fastcall Form1::ComboBox1DrawItem(TWinControl *Control, int Index,
TRect &Rect, TOwnerDrawState State)
{
TComboBox* CB = static_cast<TComboBox*>(Control);
CB->Canvas->FillRect(Rect);
boost::scoped_ptr<Graphics::TBitmap> bitmap(new Graphics::TBitmap());
bitmap->PixelFormat = pf32bit;
bitmap->AlphaFormat = afPremultiplied;
ImageList1->GetBitmap(Index, bitmap.get());
bitmap->AlphaFormat = afPremultiplied;
if (bitmap->Canvas->Handle)
{
// structure for alpha blending
BLENDFUNCTION bf;
bf.BlendOp = AC_SRC_OVER;
bf.BlendFlags = 0;
bf.SourceConstantAlpha = 0xFF; // 0x00 (transparent) through 0xFF (opaque)
bf.AlphaFormat = AC_SRC_ALPHA; // Use bitmap alpha
::AlphaBlend(CB->Canvas->Handle, // handle to destination DC
Rect.Left + 2, // x-coord of upper-left corner
Rect.Top, // y-coord of upper-left corner
bitmap->Width, // destination width
bitmap->Height, // destination height
bitmap->Canvas->Handle, // handle to source DC
0, // x-coord of upper-left corner
0, // y-coord of upper-left corner
bitmap->Width, // source width
bitmap->Height, // source height
bf // alpha-blending function
);
}
Rect = Bounds(Rect.Left + 20 + 2, Rect.Top, Rect.Right - Rect.Left, Rect.Bottom - Rect.Top);
DrawTextW(CB->Canvas->Handle, CB->Items->Strings[Index].c_str(), -1, &Rect, DT_VCENTER | DT_SINGLELINE | DT_END_ELLIPSIS);
}
The problem of course is getting a transparent TImageList1
to copy to transparent TBitmap
preserving 32-bit alpha transparency/semi-transparency. Currently I get it out with white background in the resulting TBitmap
.
Just to be clear, TImageList
ColorDepth
is set to cd32bit
with DrawingStyle = dsTransparent
before loading images to it and the images on it are transparent, no problems there.
What is the trick to solve this?
UPDATE AND MY FINAL SOLUTION
Based on a reply here here is my final working code for someone else who might need it in the future. This of course is just a template code which you might want to customize further to your own needs.
void __fastcall TForm1::ComboBox1DrawItem(TWinControl *Control, int Index, TRect &Rect, TOwnerDrawState State)
{
if (Index >= 0)
{
TComboBox* CB = static_cast<TComboBox*>(Control);
CB->Canvas->FillRect(Rect);
// Note - ImageList1 already has DrawingStyle set to dsTransparent
ImageList1->Draw(CB->Canvas, Rect.Left + 2, Rect.Top, 0);
Rect = Bounds(Rect.Left + ImageList1->Width + 2 + 2, Rect.Top, Rect.Right - Rect.Left - ImageList1->Width - 2, Rect.Bottom - Rect.Top);
DrawTextW(CB->Canvas->Handle, CB->Items->Strings[Index].c_str(), -1, &Rect, DT_VCENTER | DT_SINGLELINE | DT_END_ELLIPSIS);
}
}
You don't need to try and grab the original bitmap from the imagelist because the imagelist itself knows how to draw honoring transparency information. You can use its Draw
method for that.
Otherwise, an answer here suggests that setting AlphaFormat
to 'afIgnored' before calling GetBitmap
should preserve transparency.