Results 1 to 11 of 11

Thread: Mouse Pointer flicker using SetCursor on MouseMove

  1. #1

    Thread Starter
    New Member
    Join Date
    May 2021
    Posts
    4

    Mouse Pointer flicker using SetCursor on MouseMove

    I have a textbox control that I've made that I'm using within a combobox control. The textbox control also has some picture controls within it and I had been using the following to handle the mouse cursor with the pictures.
    Code:
    Private Sub Icon_pic_MouseMove(Index As Integer, Button As Integer, Shift As Integer, X As Single, Y As Single)
        Call SetCursor(LoadCursor(0, IDC_HAND))
    End Sub
    I prefer to do it the way above rather than setting MousePointer = 99 and loading the MouseIcon because this uses whatever hand icon the computer will use for the rest of the program. The problem, that I was ignoring until recently, is that I'm getting a flicker as I believe it is showing the default MousePointer and then running the code within MouseMove. The reason I'm not ignoring it anymore is because of the combobox I want to change the icon, when over the textbox, to the hand icon as well. This creates a lot more room the mouse can travel over to result in flicker.

    I've looked over the related threads here that I could find and I didn't find any mention of flicker so I'm wondering if I'm just missing something or being more picky. I've thought about using LoadCursor to get the hand image used by the computer and then save that and stuff it into MouseIcon but I have no idea to do it. So I'm hoping there might be someone that can point me in the right direction. Thank you in advance and sorry if I've missed laying anything out.

  2. #2
    PowerPoster
    Join Date
    Feb 2006
    Posts
    24,482

    Re: Mouse Pointer flicker using SetCursor on MouseMove

    HandCursor.cls:

    Code:
    Option Explicit
    '
    'Edit this .CLS file using a text editor to assign:
    '
    '   Attribute VB_PredeclaredId = True
    '
    '... which results in a predeclared global instance.
    '
    
    Private Const WIN32_NULL As Long = 0
    Private Const WIN32_TRUE As Long = 1
    
    Private Type IID
        Data1 As Long
        Data2 As Integer
        Data3 As Integer
        Data4(0 To 7) As Byte
    End Type
    
    Private Declare Function IIDFromString Lib "ole32" ( _
        ByVal lpsz As Long, _
        ByRef IID As IID) As Long
    
    Private Const IDC_HAND As Long = 32649 'Requires Win98 or later.
    
    Private Declare Function LoadCursor Lib "user32" Alias "LoadCursorW" ( _
        ByVal hInstance As Long, _
        ByVal lpCursorName As Long) As Long
    
    Private Type PICTDESC_ICO
        cbSizeofStruct As Long
        picType As Long
        hIcon As Long
    End Type
    
    Private Declare Function OleCreatePictureIndirect Lib "olepro32" ( _
        ByRef PICTDESC_ICO As PICTDESC_ICO, _
        ByRef IID As IID, _
        ByVal fOwn As Long, _
        ByRef pvObj As IPicture) As Long
    
    Private mPicture As IPicture
    
    Public Property Get Picture() As IPicture
        Set Picture = mPicture
    End Property
    
    Private Sub Class_Initialize()
        Dim hCursor As Long
        Dim PICTDESC_ICO As PICTDESC_ICO
        Dim IID As IID
    
        hCursor = LoadCursor(WIN32_NULL, IDC_HAND)
        If hCursor <> WIN32_NULL Then
            With PICTDESC_ICO
                .cbSizeofStruct = Len(PICTDESC_ICO)
                .picType = vbPicTypeIcon
                .hIcon = hCursor
            End With
            IIDFromString StrPtr("{7BF80980-BF32-101A-8BBB-00AA00300CAB}"), IID
            OleCreatePictureIndirect PICTDESC_ICO, IID, WIN32_TRUE, mPicture
        End If
    End Sub
    Then anywhere you need it in your program use HandCursor.Picture to retrieve a reference to the wrapped hCursor.

  3. #3
    PowerPoster
    Join Date
    Feb 2006
    Posts
    24,482

    Re: Mouse Pointer flicker using SetCursor on MouseMove

    You can also just unroll this Class as inline code if you prefer that.

  4. #4
    Addicted Member
    Join Date
    Oct 2011
    Posts
    179

    Re: Mouse Pointer flicker using SetCursor on MouseMove

    Another option is to subclass Icon_pic and to eat (not forward) WM_SETCURSOR messages.

  5. #5
    Fanatic Member
    Join Date
    Aug 2016
    Posts
    597

    Re: Mouse Pointer flicker using SetCursor on MouseMove

    Quote Originally Posted by dilettante View Post
    HandCursor.cls:

    Code:
    Option Explicit
    '
    'Edit this .CLS file using a text editor to assign:
    '
    '   Attribute VB_PredeclaredId = True
    '
    '... which results in a predeclared global instance.
    '
    
    Private Const WIN32_NULL As Long = 0
    Private Const WIN32_TRUE As Long = 1
    
    Private Type IID
        Data1 As Long
        Data2 As Integer
        Data3 As Integer
        Data4(0 To 7) As Byte
    End Type
    
    Private Declare Function IIDFromString Lib "ole32" ( _
        ByVal lpsz As Long, _
        ByRef IID As IID) As Long
    
    Private Const IDC_HAND As Long = 32649 'Requires Win98 or later.
    
    Private Declare Function LoadCursor Lib "user32" Alias "LoadCursorW" ( _
        ByVal hInstance As Long, _
        ByVal lpCursorName As Long) As Long
    
    Private Type PICTDESC_ICO
        cbSizeofStruct As Long
        picType As Long
        hIcon As Long
    End Type
    
    Private Declare Function OleCreatePictureIndirect Lib "olepro32" ( _
        ByRef PICTDESC_ICO As PICTDESC_ICO, _
        ByRef IID As IID, _
        ByVal fOwn As Long, _
        ByRef pvObj As IPicture) As Long
    
    Private mPicture As IPicture
    
    Public Property Get Picture() As IPicture
        Set Picture = mPicture
    End Property
    
    Private Sub Class_Initialize()
        Dim hCursor As Long
        Dim PICTDESC_ICO As PICTDESC_ICO
        Dim IID As IID
    
        hCursor = LoadCursor(WIN32_NULL, IDC_HAND)
        If hCursor <> WIN32_NULL Then
            With PICTDESC_ICO
                .cbSizeofStruct = Len(PICTDESC_ICO)
                .picType = vbPicTypeIcon
                .hIcon = hCursor
            End With
            IIDFromString StrPtr("{7BF80980-BF32-101A-8BBB-00AA00300CAB}"), IID
            OleCreatePictureIndirect PICTDESC_ICO, IID, WIN32_TRUE, mPicture
        End If
    End Sub
    Then anywhere you need it in your program use HandCursor.Picture to retrieve a reference to the wrapped hCursor.
    Is it necessary to DestroyCursor before Class terminating?

    Attribute VB_PredeclaredId = True
    What is this flag function? It's new for me. Please give me tuitions.

  6. #6
    PowerPoster
    Join Date
    Feb 2006
    Posts
    24,482

    Re: Mouse Pointer flicker using SetCursor on MouseMove

    DestroyCursor() is only for non-shared cursors. The hand cursor is a system stock cursor and so always shared. In any case the Picture object was given ownership of the handle via the OleCreatePictureIndirect() call made here, so it takes care of handle management.


    VB_PredeclaredId is True by default for Forms, which is why you have a Form class and one global Form instance with the same name as the Form in VB6.

    You can use this same setting in a VB6 Class module to get a global Class instance with the same name as the Class. But for Class modules it is False by default. The VB IDE had not been enhanced with a way to assign this True before VB was killed off after VB6. So you have to manually edit in Notepad or something to do it. It isn't documented, but it is well known and has been stable for almost 25 years.

    Code:
    VERSION 1.0 CLASS
    BEGIN
      MultiUse = -1  'True
      Persistable = 0  'NotPersistable
      DataBindingBehavior = 0  'vbNone
      DataSourceBehavior  = 0  'vbNone
      MTSTransactionMode  = 0  'NotAnMTSObject
    END
    Attribute VB_Name = "HandCursor"
    Attribute VB_GlobalNameSpace = False
    Attribute VB_Creatable = True
    Attribute VB_PredeclaredId = True
    Attribute VB_Exposed = False
    Option Explicit

  7. #7
    PowerPoster
    Join Date
    Feb 2006
    Posts
    24,482

    Re: Mouse Pointer flicker using SetCursor on MouseMove

    But you can just ignore that and create an instance, use it, then dispose of it. The thing you need is to get that Picture object that you can assign to the MouseIcon property.

  8. #8
    Fanatic Member
    Join Date
    Aug 2016
    Posts
    597

    Re: Mouse Pointer flicker using SetCursor on MouseMove

    very detailed, thank expert dilettante.

  9. #9
    PowerPoster
    Join Date
    Feb 2006
    Posts
    24,482

    Re: Mouse Pointer flicker using SetCursor on MouseMove

    Your question about DestroyCursor() was a good one. This changed version is probably more correct because it stops the Picture object from trying to destroy the shared cursor:

    Code:
    Option Explicit
    '
    'Edit this .CLS file using a text editor to assign:
    '
    '   Attribute VB_PredeclaredId = True
    '
    '... which results in a predeclared global instance.
    '
    
    Private Const WIN32_NULL As Long = 0
    Private Const WIN32_FALSE As Long = 0
    
    Private Type IID
        Data1 As Long
        Data2 As Integer
        Data3 As Integer
        Data4(0 To 7) As Byte
    End Type
    
    Private Declare Function IIDFromString Lib "ole32" ( _
        ByVal lpsz As Long, _
        ByRef IID As IID) As Long
    
    Private Const IDC_HAND As Long = 32649 'Requires Win98 or later.
    
    Private Declare Function LoadCursor Lib "user32" Alias "LoadCursorW" ( _
        ByVal hInstance As Long, _
        ByVal lpCursorName As Long) As Long
    
    Private Type PICTDESC_ICO
        cbSizeofStruct As Long
        picType As Long
        hIcon As Long
    End Type
    
    Private Declare Function OleCreatePictureIndirect Lib "olepro32" ( _
        ByRef PICTDESC_ICO As PICTDESC_ICO, _
        ByRef IID As IID, _
        ByVal fOwn As Long, _
        ByRef pvObj As IPicture) As Long
    
    Private mPicture As IPicture
    
    Public Property Get Picture() As IPicture
        Set Picture = mPicture
    End Property
    
    Private Sub Class_Initialize()
        Dim hCursor As Long
        Dim PICTDESC_ICO As PICTDESC_ICO
        Dim IID As IID
    
        hCursor = LoadCursor(WIN32_NULL, IDC_HAND)
        If hCursor <> WIN32_NULL Then
            With PICTDESC_ICO
                .cbSizeofStruct = Len(PICTDESC_ICO)
                .picType = vbPicTypeIcon
                .hIcon = hCursor
            End With
            IIDFromString StrPtr("{7BF80980-BF32-101A-8BBB-00AA00300CAB}"), IID
            'This is a shared cursor, do not call DestroyCursor (fOwn should be false):
            OleCreatePictureIndirect PICTDESC_ICO, IID, WIN32_FALSE, mPicture
        End If
    End Sub

  10. #10

    Thread Starter
    New Member
    Join Date
    May 2021
    Posts
    4

    Re: Mouse Pointer flicker using SetCursor on MouseMove

    Thank you so much dilettante! Worked like a gem and had a good lesson as well.

  11. #11
    PowerPoster wqweto's Avatar
    Join Date
    May 2011
    Location
    Sofia, Bulgaria
    Posts
    5,120

    Re: Mouse Pointer flicker using SetCursor on MouseMove

    Btw, here is a shorter (a single function) impl

    Code:
    Option Explicit
    
    Private Declare Function LoadCursor Lib "user32" Alias "LoadCursorW" (ByVal hInstance As Long, ByVal lpCursorName As Long) As Long
    Private Declare Function OleCreatePictureIndirect Lib "olepro32" (lpPictDesc As Any, riid As Any, ByVal fOwn As Long, lpvObj As stdole.IUnknown) As Long
        
    Public Function GetHandCursor() As StdPicture
        Const IDC_HAND      As Long = 32649
        Dim aDesc(0 To 2)   As Long
        Dim IID_IUnknown(0 To 3) As Long
                        
        aDesc(0) = 12
        aDesc(1) = vbPicTypeIcon
        aDesc(2) = LoadCursor(0, IDC_HAND)
        IID_IUnknown(2) = &HC0
        IID_IUnknown(3) = &H46000000
        Call OleCreatePictureIndirect(aDesc(0), IID_IUnknown(0), 0, GetHandCursor)
    End Function
    Can be used like this

    Code:
    Private Sub Form_Load()
        MousePointer = MousePointerConstants.vbCustom
        Set MouseIcon = GetHandCursor
    End Sub
    cheers,
    </wqw>

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Click Here to Expand Forum to Full Width