So yesterday I talked about making a translucent button in WinForms using VB.NET. If you have not read that yet, then you should probably do so before digging into part 2, where we expand part 1 to cover more controls.
Today lets look at making a translucent TabPage control.
Here is our end result:

So we have a nice cherry sunburst Gibson Les Paul as our form background, with a TabControl overlaying it, with a few buttons on it.
So what is different about the implementation of the translucent tab control versus the buttons we did last time? Well for starters, the translucent painting of the background needs to be done on the TabPages which are the individual tab objects that the TabControl contains.
I am not going to redefine all the code used for this control, as much of it is the same as from the button control. The full source of the project is attached to this post, so you can download that for all the code.
I will go over the specific differences between the button and the TabControl so you can see what we had to do differently.
The first thing is, we want to make the control translucent regardless of what tab is currently selected. So we need to track controls being added or removed from the TabControl. TabControls can ONLY have TabPages added to their controls collection, otherwise the framework throws an error. So we wire up the OnControlAdded and OnControlRemoved event handlers to add or remove the given TabPage from being custom drawn as translucent.
#Region "OVERRIDES TO HANDLE CHILD TABPAGES"
Protected Overrides Sub OnControlAdded( _
ByVal e As System.Windows.Forms.ControlEventArgs)
AddHandler DirectCast(e.Control, TabPage).Paint, _
AddressOf DrawFormBackgroundOnTabPage
MyBase.OnControlAdded(e)
End Sub
Protected Overrides Sub OnControlRemoved( _
ByVal e As System.Windows.Forms.ControlEventArgs)
RemoveHandler DirectCast(e.Control, TabPage).Paint, _
AddressOf DrawFormBackgroundOnTabPage
MyBase.OnControlRemoved(e)
End Sub
#End Region
Note the DrawFormBackgroundOnTabPage method we are wiring up. We will define that next.
#Region "CUSTOM PAINTING ROUTINE"
Private Sub DrawFormBackgroundOnTabPage(ByVal sender As Object, _
ByVal e As PaintEventArgs)
'DON'T DO ANY CUSTOM PAINTING IF THE FEATURE IS DISABLED
If Not _isTranslucent Then Return
Dim myTab As TabPage = DirectCast(sender, TabPage)
'GET THE CONTROL THAT THE IMAGE IS ON WE WANT TO USE FOR TRANSLUCENCY
Dim parentControl As Control = Nothing
If _backgroundImageSource = _
ITranslucentControl.eBackgroundImageSource.Form Then
'GET FORM
parentControl = Me.FindForm
Else
'GET PARENT (WILL BE FORM IF NO CONTAINER EXISTS)
parentControl = Me.Parent
End If
'IF THE PARENT CONTROL WE ARE REFERNCING HAS NO
'BACKGROUND IMAGE, DO NOTHING
'ALSO CHECK TO MAKE SURE STRETCH IS THE LAYOUT TYPE
If parentControl.BackgroundImage Is Nothing Then Return
If parentControl.BackgroundImageLayout <> _
ImageLayout.Stretch Then Return
'SOURCE RECTANGLE IS THE CLIPPED REGION OF THE
'FORMS BACKGROUND IMAGE THAT IS BEHIND THE TABPAGE.
'CLIPPING ALLOWS US TO THEN PASTE THE COVERED PART
'OF THE FORM BACKGROUND IMAGE ONTO THE LISTVIEW
'BACKGROUND TO MIMIC TRANSPARENCY
Dim srcRect As Rectangle = Nothing
If _backgroundImageSource = _
ITranslucentControl.eBackgroundImageSource.Form Then
srcRect = New Rectangle(GetPointFromForm(myTab), myTab.Size)
Else
srcRect = New Rectangle( _
(myTab.Left + Me.Left), _
(myTab.Top + Me.Top), _
myTab.ClientRectangle.Width, _
myTab.ClientRectangle.Height)
End If
'IMAGE WITH THE CURRENT CLIENT SIZE OF THE BACKGROUND
Dim mySourceImage As New Bitmap(parentControl.BackgroundImage, _
parentControl.ClientSize.Width, _
parentControl.ClientSize.Height)
'IMAGE ATTRIBUTES SO WE CAN SET GAMMA (TO MAKE IMAGE LIGHTER)
Dim image_attr As New Drawing.Imaging.ImageAttributes
image_attr.SetGamma(_gamma)
'DRAW THE CROPPED IMAGE ONTO THE TABPAGE
e.Graphics.DrawImage(mySourceImage, _
myTab.ClientRectangle, _
(srcRect.X + _Offset.X), _
(srcRect.Y + _Offset.Y), _
srcRect.Width, _
srcRect.Height, _
GraphicsUnit.Pixel, _
image_attr)
image_attr.Dispose()
image_attr = Nothing
End Sub
#End Region
The concept we use is the same as the buttons, however sender is always going to be a TabPage, so we grab that at the start of the routine, and use it as our painting canvas. The key difference is we actually paint the background onto the TabPage, where as the button got its backgroundimage property assigned to the image we wanted to show. There is also a little bit of additional positioning code, to account for the parent of the TabPage, which is the containing TabControl. Since the TabControl has the actual tabs on it, we need to take that into account, otherwise the section of the background we grab to paint on the tabs will be badly offset.
Remember for a full rundown, read part 1: Translucent Button in WinForms
As always, send me your comments or code improvements if you happen to find any.
Posted
May 06 2008, 01:14 PM
by
Matthew Kleinwaks