HotTrack on TabControl with Draw mode of OwnerDrawFixed in VB-VS20

  • Thread starter Thread starter Guest
  • Start date Start date
G

Guest

I'm trying to implement a custom look on selected tabs on a tab control.
I've done this successfully. However, I noticed that when I set the draw
mode to OwnerDrawFixed the HotTrack property is ignored.

I figured this was by design and tried to implement it in the method I'm
using for drawing the item but the e.state (where e is DrawItemEventArgs) is
never DrawItemState.HotLight. It is only None or Selected (0 or 1).

Is this a bug or by design? Is there any way to implement the hot tracking
with tabs via the draw item event for an owner drawn tab control?
 
Private Sub TabControl1_DrawItem(ByVal sender As Object, _
ByVal e As System.Windows.Forms.DrawItemEventArgs) _
Handles TabControl1.DrawItem
Dim tabRect As Rectangle = TabControl1.GetTabRect(e.Index)
e.Graphics.Clip = New Region(tabRect)

'HotTrack Implementation
If tabRect.Contains(TabControl1.PointToClient(Cursor.Position)) _
AndAlso TabControl1.HotTrack Then

e.Graphics.Clear(Color.Red)
Else
e.Graphics.Clear(Color.Blue)
End If
e.Graphics.ResetClip()
End Sub
 
Thanks for the response. I'd actually tried a similar implementation. The
problem is that sometimes it doesn't seem to redraw when you leave a tab, and
leaves it hottracked.

Any ideas why?
 
Are you inflating the tabRect size when e.index = selectedindex, so that you
can erase the 3d line? If so then make sure you reset the tabRect size
before using it to assign a clip region.

Are you trying to draw outside of the tabs and completely change the
appearance of the TabControl?
Then you should take a different approach entirely. See the A Completely
OwnerDraw TabControl example on my site:
http://www.dotnetrix.co.uk/tabcontrols.html

....or the A .Net Flat TabControl example on CodeProject (C#):
http://www.codeproject.com/useritems/FlatTabControl.asp#xx1297405xx
 
Here's what I'm using right now. This doesn't hottrack, but does change the
appearence of the selected tab.

Is there a better way with your method? When I used JUST your method though,
I still noticed a problem of it not removing the hottracking when you moused
out of a tab.

If (e.Index = ptcTabControl.SelectedIndex) Then
zfntFont = New Font(e.Font, FontStyle.Bold Or FontStyle.Bold)
zbrsForeBrush = New SolidBrush(e.ForeColor)
zbrsBackBrush = New
System.Drawing.SolidBrush(Color.LightSteelBlue)
Else
zfntFont = e.Font
zbrsForeBrush = New SolidBrush(e.ForeColor)
zbrsBackBrush = New
System.Drawing.SolidBrush(SystemColors.Control)

End If

Dim zstrTabName As String = ptcTabControl.TabPages(e.Index).Text
Dim zsfStringFormat As StringFormat = New StringFormat
zsfStringFormat.Alignment = StringAlignment.Center
e.Graphics.FillRectangle(zbrsBackBrush, e.Bounds)
Dim zrecRectangle As Rectangle = e.Bounds
zrecRectangle = New Rectangle(zrecRectangle.X, zrecRectangle.Y +
1, zrecRectangle.Width, zrecRectangle.Height - 1)
e.Graphics.DrawString(zstrTabName, zfntFont, zbrsForeBrush,
zrecRectangle, zsfStringFormat)

zsfStringFormat.Dispose()


zfntFont.Dispose()
zbrsBackBrush.Dispose()
zbrsForeBrush.Dispose()
 
Firstly;
May I suggest that you turn on Option Explicit so that you will be warned
about bad coding habits.
DrawText is expecting a RectangleF not a Rectangle.
Else
zfntFont = e.Font
zfntFont.Dispose()

You cannot Dispose e.Font because it does not belong to you (I expect that
you didn't paste the exact code you're using as this would never have run
unless you only have one tab).

....and now back to your question;
You shouldn't see this HotTrack problem when using my method, but you will
see it when using yours.

You will notice that I don't use e.Bounds (except when painting the
SelectedTab) but instead use the TabControls GetTabRect() method. This
results in a rectangle that is smaller than the one returned by e.Bounds and
is the size of the tab inside it's borders, so the TabControl does not get
upset by you trying to paint an area that OwnerDrawFixed does not allow you
to paint.

Here's a modification to your method that should work as expected (it does
here):

\\\
Dim zfntFont As Font = New Font(e.Font, e.Font.Style)
Dim zbrsForeBrush, zbrsBackBrush As Brush

zbrsForeBrush = New SolidBrush(e.ForeColor)

If (e.Index = TabControl1.SelectedIndex) Then
If e.Font.FontFamily.IsStyleAvailable(FontStyle.Bold) Then
zfntFont = New Font(e.Font, FontStyle.Bold)
End If
End If

Dim zstrTabName As String = ptcTabControl.TabPages(e.Index).Text
Dim zsfStringFormat As StringFormat = New StringFormat
zsfStringFormat.Alignment = StringAlignment.Center
zsfStringFormat.LineAlignment = StringAlignment.Center

Dim zrecRectangle As Rectangle = ptcTabControl.GetTabRect(e.Index)
Dim fillColor As Color
If zrecRectangle.Contains(ptcTabControl.PointToClient(Cursor.Position)) _
AndAlso ptcTabControl.HotTrack Then
fillColor = Color.Red
Else
fillColor = SystemColors.Control
End If
If e.Index = ptcTabControl.SelectedIndex Then
fillColor = Color.LightSteelBlue
zrecRectangle = e.Bounds
End If
e.Graphics.Clip = New Region(zrecRectangle)
e.Graphics.Clear(fillColor)
e.Graphics.ResetClip()

e.Graphics.DrawString(zstrTabName, zfntFont, zbrsForeBrush, _
RectangleF.op_Implicit(zrecRectangle), zsfStringFormat)

zsfStringFormat.Dispose()
zfntFont.Dispose()
zbrsForeBrush.Dispose()
///
 
I appreciate it, but the problem is the same with just your code and none of
mine.

In a multiline tab control where the tabcontrol is on the bottom.
I have two rows of 3 tabs each. When I drag the mouse from the bottom row to
the top on the center column of tabs, the bottom center tab stays hottracked,
and the top tab getss hottracked. This results in two hottracked tabs.
 
OK, I hadn't tried that. It would appear to be a bug.
The only workaround I can suggest is to Inherit TabControl and go the
Completely OwnerDraw method that I mentioned earlier. The downside to this
is that it's a lot of work, but you should get exactly what you want.

You could just Invalidate the control in MouseMove/MouseLeave events, but I
don't think you'd be happy with the Flicker.
Maybe you could set a HotTab Flag in the MouseMove/MouseLeave events and
Invalidate just the previous HotTab rectangle when it's changed, but I'm not
sure that this would be any better.

If all you're trying to do is Bold the selected item, whilst still using
HotTrack, and don't want to do all the work involved in the Completely
OwnerDraw Method, then try my TabControlEX (I've already done all the work).
It has a SelectedTabFontStyle property just for this, and it's Free. It also
has several other frequently requested features that the standard TabControl
does not have.
http://www.dotnetrix.co.uk/controls.html
 
Back
Top