-
May 27th, 2022, 01:39 PM
#1
Thread Starter
New Member
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.
-
May 27th, 2022, 03:46 PM
#2
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.
-
May 27th, 2022, 04:12 PM
#3
Re: Mouse Pointer flicker using SetCursor on MouseMove
You can also just unroll this Class as inline code if you prefer that.
-
May 27th, 2022, 05:12 PM
#4
Addicted Member
Re: Mouse Pointer flicker using SetCursor on MouseMove
Another option is to subclass Icon_pic and to eat (not forward) WM_SETCURSOR messages.
-
May 27th, 2022, 06:59 PM
#5
Fanatic Member
Re: Mouse Pointer flicker using SetCursor on MouseMove
Originally Posted by dilettante
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.
-
May 27th, 2022, 09:33 PM
#6
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
-
May 27th, 2022, 09:52 PM
#7
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.
-
May 27th, 2022, 10:27 PM
#8
Fanatic Member
Re: Mouse Pointer flicker using SetCursor on MouseMove
very detailed, thank expert dilettante.
-
May 27th, 2022, 10:49 PM
#9
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
-
May 31st, 2022, 07:03 AM
#10
Thread Starter
New Member
Re: Mouse Pointer flicker using SetCursor on MouseMove
Thank you so much dilettante! Worked like a gem and had a good lesson as well.
-
May 31st, 2022, 07:25 AM
#11
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
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|