Click here to Skip to main content
15,902,112 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
I have been working on my first custom user control. The custom control inherits UserControl. The user control contains a combination of drawn rectangles, circles and a icon image. I would like to display a tool tip when the user hovers the mouse over the image portion of the control. The image was created by using drawicon. I then have a mouse move event in my control that detects when the mouse is over the icon. That logic all works properly. What I am having a problem with is that after the tool tip disappears, it erases the part of the control is was hovering over. I am trying to figure out the proper way to repaint the control but I am not having any luck.

What I have tried:

Here is how I am painting the control:
Protected Overrides Sub OnPaint(ByVal e As System.Windows.Forms.PaintEventArgs)

        Dim rect As System.Drawing.Rectangle = e.ClipRectangle
        Dim g As Graphics = e.Graphics
        g.SmoothingMode = SmoothingMode.HighQuality

        'Draw the Machine Bed
        DrawBed(g, rect)

        'Draw and position the Machine Head
        DrawHead(g, rect, _HeadPosInInches)

    End Sub

    Private Sub DrawBed(ByVal g As Graphics, ByVal CtlRect As System.Drawing.Rectangle)

        'Draws the bed

        'Size the bed based on the control size
        _BedWidth = CInt(CtlRect.Width * _BedWidthFactor)
        _BedHeight = CInt(CtlRect.Height * _BedHeightFactor)

        'Center the bed within the control
        _BedYBorder = CInt((CtlRect.Height - _BedHeight) / 2)
        _BedXBorder = CInt(CtlRect.Width - _BedWidth)

        'Create a new rect for the bed
        Dim BedXLoc As Integer = 0

        If HeadTravelDir = 1 Then
            BedXLoc = _BedXBorder
            BedXLoc = 0
        End If

        Dim BedRect As New Rectangle(BedXLoc, _BedYBorder, _BedWidth, _BedHeight)

        'Fill the Bed
        Using Brush1 As New SolidBrush(_BedColor)
            g.FillRectangle(Brush1, BedRect)
        End Using

        'Create the Bed border
        Using Pen1 As New Pen(Color.Black, 1)
            g.DrawRectangle(Pen1, BedRect)
        End Using

    End Sub

Here is how I am drawing the icon image on the screen:

Dim TargetX As Integer = 0
Dim TargetY As Integer = 0
Dim TargetWidth As Integer = _BedYBorder
Dim TargetHeight As Integer = _BedYBorder

If _HeadTravelDir = 1 Then
   TargetX = HeadRect.X + HeadRect.Width + 5
   TargetX = HeadRect.X - 5 - _BedYBorder
End If

Dim DashboardIcon As New Icon("U:\photos\DashboardIcons\Question.ico")
Dim TargetRect As New Rectangle(TargetX, TargetY, TargetWidth, TargetHeight)
IconRect = TargetRect
g.DrawIcon(DashboardIcon, TargetRect)

Here is how I am detecting when the mouse if over the icon image:

Private Sub ctlGantry_MouseMove(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles Me.MouseMove

        'Checks to see if the mouse if over the icon
        If IconRect.Contains(e.Location) Then
            Debug.WriteLine(e.Location.ToString & " is Over the Icon for " & Me.Name)
            _IconMouseOver = True
            'Me.ToolTip1.Show("test", Me)

            _IconMouseOver = False
        End If
    End Sub

I have tried displaying the tooltip in both the mousemove and the mousehover events but I get similar results. If I try to invalidate when the mouse is not over the icon, I get a lot of flickering. The background control also doesn't repaint when I move the mouse in a different position over the icon. I am not sure if this is related to the same issue but I also have a problem where the icon will no longer reappear after I hover on the control for a few seconds and then comeback and rehover. If I repaint the control and try it again, then the tooltip will reappear. I am very close to being able to wrap this control up but I need to figure this out first. Any ideas?
Updated 9-Aug-17 2:56am
Graeme_Grant 9-Aug-17 2:12am    
Are you rendering in the UserControl_Paint event [if the UserControl is your canvas] and calling UserControl.Invalidate() method to force repaint when updating the UI?
theskiguy 9-Aug-17 7:18am    
You are correct. See improved question that now includes some code that show the control painting. As far as Invalidate, the problem I am having is determining the proper time to call it. If I only call invalidate when the mouse is not over the icon, the control will not repaint if I move the mouse to a different position on the icon. If I move the invalidate to the beginning of the mouse move event, my user control completely disappears even if I stop moving the mouse when it is over the icon.
Graeme_Grant 9-Aug-17 9:03am    
I'm not seeing the problem with the code that you provided. So instead I've knocked up a little test and everything is working as expected. Hope it helps.

1 solution

Here is a working sample for you:
Public Class UserControl1

    Public Sub New()


    End Sub

    Private Tooltip As ToolTip

    Private Sub AddTootip()

        Tooltip = New ToolTip() With
            .AutoPopDelay = 5000,
            .InitialDelay = 1000,
            .ReshowDelay = 500,
            .ShowAlways = True
        Tooltip.SetToolTip(Me, "Test tooltip 1 2 3...")

    End Sub

    Private boxes(9) As Rectangle

    Private Sub UserControl1_Paint(sender As Object, e As PaintEventArgs) Handles MyBase.Paint

        Dim gr = e.Graphics
        Dim br = New SolidBrush(Color.Red)

        For index = 0 To 9
            gr.FillRectangle(br, boxes(index))

    End Sub

    Private Sub UserControl1_MouseMove(sender As Object, e As MouseEventArgs) Handles MyBase.MouseMove

        For index = 0 To 9
            If boxes(index).Contains(e.Location) Then
                Tooltip.ToolTipTitle = "Box " + CStr(index + 1)
                Exit Sub
            End If
        Tooltip.ToolTipTitle = "UserControl background..."

    End Sub

    Private Sub UserControl1_Resize(sender As Object, e As EventArgs)
    End Sub

    Private Sub Recalc()

        Dim hoffset = Height / 11
        Dim woffset = Width / 11
        Dim sz = New Size(woffset, hoffset)

        For index = 0 To 9
            Dim pt = New Point(index * woffset, index * hoffset)
            boxes(index) = New Rectangle(pt, sz)


    End Sub

End Class
Share this answer
theskiguy 11-Aug-17 14:25pm    
Your solution works great but I still can't figure out while mine doesn't work. I guess I will have to start a new project from scratch and keep it simple at the start until I figure out the cause.

As a side note I did have a few syntax errors in your example that I had to address so I thought I would bring it to your attention so you could update your code. I had to update the syntax for the "With" statement in your AddToolTip sub. I also had to declare the "Index" variables in mouse_move,Recalc and paint subs. Thanks for your help. If I finally figure out what caused my issue, I will let you know. Thanks.
Graeme_Grant 11-Aug-17 18:19pm    
Sorry, I moved from VB to C# a couple of years ago... Those Syntax errors could be your version of Visual Studio. This was done on VS2017 and compiled successfully. For older than VS2016(?), you may need to add underscores for line continuation...

Good luck with your project. :)

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900