'je dois de dire un merci aux personnes ci-dessous:
'Daetips pour sa source
http://www.vbfrance.com/codes/MOUSE-WHEEL-EVENTS-EVENEMENTS-MIDDLE_MOUSE_DOWN-MIDDLE_MOUSE_UP-MIDDLE_MOUSE_DOUBLE_CLICK-DLL_32546.aspx
'Philippe734 qui est ma reference vbfrance sur le sujet avec sa source de reference
http://www.vbfrance.com/codes/UTILISATION-MOLETTE-ROULETTE-SOURIS_25201.aspx
'EBArtSoft et sa source
http://www.vbfrance.com/codes/UTILISER-ROULETTE-DANS-VB6-IDE-ADDIN_21802.aspx
'Ca fait 2 Jours depuis le 11/2 que je me plonge pour la premiere fois dans le subclassing dont j'ai toujours entendu parler dans ce forum et reservé aux initiés
'Au début je voulais juste faire marcher la molette dans mes datagrid et hop voila je me suis retrouve dans un monde magique dont je me demande encore comment j'ai pu m'en passer.
Le problème en lui même est déjà connu et a eu des solutions diverses interessantes pour la plupart mais mon approche est originale, intuitive et simple comme dab.
'Le concept de cet OCX est 100% de moi, et il offre un niveau de souplesse un petit poil au dessus sur la source géniale de Daetips
'Il est autonome et n'a pas besoin d'utiliser le génial fichier Wheel.tlb d'EBArtSoft
'Pas besoin de charger quoi que ce soit du registre, le pas de la roulette est un propriété du contrôle.
'Il suffit de déposer ce contrôle ds votre form et hop les evenements de la molette sont a votre portée.
Note très importante:
--------------------
Il est important de préciser que le but premier de ce controle est d'intercepter tous les mouvements de la molette et de le renvoyer au Hwnd demandeur. La source de Daetips va essayer de traiter le scroll sur les Hwnd demandeurs, ce qui n'est pas le but que je recherche. Pourquoi? parce que je voudrais pouvoir faire interagir la molette sur un objet datagrid (par exemple) en decidant sur quel conteneur je voudrais intercepter les actions de la molette. les cas de figures sont tellement variés que j'ai besoin de traiter les actions de la molette par moi-même, exemple comment je veux que ce comporte la molette pour 2 datagrids dans un même conteneur.
Il existe aussi un autre cas de figure (Le cas pour lequel j'ai été amené absolument à me pencher sur ce problème, vu que c'est le point central de l'affichage de mes listes dans toutes mes applis), ou ce composant se trouve sur un Usercontrol en meme temps qu'un datagrid. je voudrais intercepter les mouvements de la roulette sur le Form Conteneur de cet Usercontrol et j'ai besoin de dire à l'objet sur quel Hwnd je veux qu'il intercepte les mouvements de la molette, en plus les imbrications de usercontrol peuvent ordre à plus de 2 niveaux.
Le controle intercepte les mouvements de la roulette sur le form demandeur, mais va neanmoins préciser si l'action est contenu dans la fenetre. On pourra de ce fait décider de le traiter ou pas. En plus on peut demander a l'objet de stopper la capture de la molette dur le demandeur lorsque le focus est hors de la fenetre.
L'exemple ci-dessous illustre une gestion de ce controle.
Source / Exemple :
Option Explicit
Private moRst As ADODB.Recordset
Private Sub Command1_Click()
FormB.Show
End Sub
Private Sub SNA_Wheel1_WheelAction(ByVal peWheelAction As Prj_SNAWheel.EnumWheelAction, ByVal plScrollLines As Variant, ByVal pbFocusIn As Boolean, pbWheelOff As Boolean)
If pbFocusIn Then
Select Case peWheelAction
Case wa_WheelDown:
Case wa_WheelUP:
Case wa_WheelDoubleClick:
Case wa_WheelMove: If pbFocusIn Then DataGrid1.Scroll 0, plScrollLines
End Select
Else
'Je detecte une action de la molette hors de la fenetre, je demande d'y arreter la capture
pbWheelOff = True
Debug.Print "WheelOff on Datagrid"
End If
End Sub
Private Sub Form_Activate()
'Je suis activé, alors je fais la demande de capture de la molette
With SNA_Wheel1
.hWnd = Me.hWnd
Debug.Print "Activate DataGrid"
End With
End Sub
Private Sub Form_Load()
Set DataGrid1.DataSource = moRst
End Sub
Private Sub Form_Initialize()
Set moRst = New ADODB.Recordset
With moRst
.CursorLocation = adUseClient
.Open "Select * From [Feuil1$]", _
"driver={Microsoft Excel Driver (*.xls)};DriverId=790;ReadOnly=0;FirstRowHasNames=1;DBQ=" & App.Path & "\Classeur1.xls", _
adOpenStatic, _
adLockReadOnly
End With
End Sub
Private Sub Form_Terminate()
If moRst.State = adStateOpen Then moRst.Close
Set moRst = Nothing
End Sub
Conclusion :
Je suis tenté de dire qu'il n'existe pas de bug. En effet le developpeur a tous les moyens d'orienter la capture de la molette sur l'objet de son choix.
Laissons voir les tests, retournez moi les erreurs.
A+
8 août 2010 à 22:38
Classe ClsWheel
---------------
Option Explicit
Implements ISubclasser
Private mtWin1 As SubClassedWindow
Public Event WheelAction(ByVal peWheelAction As Long, ByVal plSens As Long)
Public Sub Init(ByVal plHwnd As Long)
InitiateSubClassing mtWin1, Me, plHwnd, True
End Sub
Private Function ISubclasser_WindowProc(ByVal hWnd As Long, ByVal uMsg As MessageConstants, ByVal wParam As Long, ByVal lParam As Long) As Long
If hWnd <> mtWin1.hWnd Then Exit Function
ISubclasser_WindowProc = CallOldProc(mtWin1, hWnd, uMsg, wParam, lParam)
Select Case uMsg
Case WM_MBUTTONDOWN: RaiseEvent WheelAction(wa_WheelDown, 0)
Case WM_MBUTTONUP: RaiseEvent WheelAction(wa_WheelUP, 0)
Case WM_MBUTTONDBLCLK: RaiseEvent WheelAction(wa_WheelDoubleClick, 0)
Case WM_MOUSEWHEEL:
'wParam indique le mouvement de la molette
'pour wParam négatif, c'est pour voir en haut
'positif, on descend le curseur du scrollbar
RaiseEvent WheelAction(wa_WheelMove, IIf(wParam < 0, 1, -1))
End Select
End Function
Private Sub Class_Terminate()
TerminateSubClassing mtWin1
End Sub
Usercontrol SNA_Wheel
---------------------
Option Explicit
'Valeurs de propriétés par défaut:
Private Const m_def_ScrollLines = 3
Public Enum EnumWheelAction
wa_WheelDown = 1
wa_WheelUP = 2
wa_WheelDoubleClick = 3
wa_WheelMove = 4
End Enum
Private mlScrollLines As Long
Private WithEvents moClsWheel As ClsWheel
'Déclarations d'événements:
Public Event WheelAction(ByVal peWheelAction As EnumWheelAction, ByVal plScrollLines)
'Activation de la capture de la molette sur une fenetre, par défaut celle du conteneur
Public Sub Activate(Optional ByVal plHwnd As Long = 0)
If plHwnd = 0 Then moClsWheel.Init UserControl.Parent.hWnd Else moClsWheel.Init plHwnd
End Sub
'ATTENTION! NE SUPPRIMEZ PAS OU NE MODIFIEZ PAS LES LIGNES COMMENTÉES SUIVANTES!
'MemberInfo=8,0,0,3
Public Property Get ScrollLines() As Long
ScrollLines = mlScrollLines
End Property
Public Property Let ScrollLines(ByVal New_ScrollLines As Long)
mlScrollLines = New_ScrollLines
If Not Ambient.UserMode Then PropertyChanged "ScrollLines"
End Property
Private Sub moClsWheel_WheelAction(ByVal peWheelAction As EnumWheelAction, ByVal plSens As Long)
Select Case plSens
Case -1: RaiseEvent WheelAction(peWheelAction, -mlScrollLines)
Case 1: RaiseEvent WheelAction(peWheelAction, mlScrollLines)
Case 0: RaiseEvent WheelAction(peWheelAction, 0)
End Select
End Sub
'Initialiser les propriétés pour le contrôle utilisateur
Private Sub UserControl_InitProperties()
mlScrollLines = m_def_ScrollLines
End Sub
'Charger les valeurs des propriétés à partir du stockage
Private Sub UserControl_ReadProperties(PropBag As PropertyBag)
mlScrollLines = PropBag.ReadProperty("ScrollLines", m_def_ScrollLines)
End Sub
'Écrire les valeurs des propriétés dans le stockage
Private Sub UserControl_WriteProperties(PropBag As PropertyBag)
Call PropBag.WriteProperty("ScrollLines", mlScrollLines, m_def_ScrollLines)
End Sub
Private Sub UserControl_Initialize()
Set moClsWheel = New ClsWheel
End Sub
Private Sub UserControl_Terminate()
Set moClsWheel = Nothing
End Sub
Il suffit de déposer le composant SNA_Wheel sur un form, qu'on activera sur l'évènement Load.
Private Sub Form_Load()
SNA_Wheel1.Activate
End Sub
Les evènements seront gérés comme ci-dessous.
Private Sub SNA_Wheel1_WheelAction(ByVal peWheelAction As Prj_SNAWheel.EnumWheelAction, ByVal plScrollLines As Variant)
Select Case peWheelAction
Case wa_WheelDoubleClick: Label1.Caption = "Wheel DoubleClick"
Case wa_WheelDown: Label1.Caption = "Wheel Down"
Case wa_WheelMove: Label1.Caption = "Wheel Move - Step=" & plScrollLines
Case wa_WheelUP: Label1.Caption = "Wheel Up"
End Select
End Sub
Question : Le composant étant invisible en mode runtime, l'évènement Show du Usercontrol est sans effet, comment pourrait-on faire pour que la capture de la molette s'active automatiquement sur l'évènement Load du form conteneur?. Le but étant de se passer de SNA_Wheel1.Activate sur Load. Le top étant d'avoir la capture par le seul fait de déposer le composant dans une form.
8 août 2010 à 18:19
3 août 2010 à 00:16
' Dans un module de class nommé CMouseWheel :
Implements ISubclasser
Private mtWin1 As SubClassedWindow
Public Event MouseWheel(Orientation As Long, Click As Boolean)
Public Sub AttachTo(frm As Form)
InitiateSubClassing mtWin1, Me, frm.hWnd, True
End Sub
Private Sub Class_Terminate()
TerminateSubClassing mtWin1
End Sub
Private Function ISubclasser_WindowProc(ByVal hWnd As Long, ByVal uMsg As MessageConstants, ByVal wParam As Long, ByVal lParam As Long) As Long
If hWnd <> mtWin1.hWnd Then Exit Function
ISubclasser_WindowProc = CallOldProc(mtWin1, hWnd, uMsg, wParam, lParam)
If uMsg = WM_MOUSEWHEEL Then RaiseEvent MouseWheel(Sgn(wParam), False)
If uMsg = WM_MBUTTONUP Then RaiseEvent MouseWheel(Sgn(wParam), True)
End Function
' Intégration de l'évènement molette dans une form :
Private WithEvents FormX As CMouseWheel
Private Sub Form_Load()
Set FormX = New CMouseWheel
FormX.AttachTo Me
End Sub
Private Sub FormX_MouseWheel(Orientation As Long, Click As Boolean)
'If Orientation < 0 Then ' On scroll vers le bas
End Sub
Bon, tout ça pour dire que c'est juste pour le plaisir d'utiliser le subclassing facilement.
27 juil. 2010 à 22:45
vbfrance.com/codes/MODULE-SUBCLASSER_38442.aspx
18 févr. 2010 à 07:34
Quelle importance me diriez-vous vu que chaque objet a deja sa propre gestion d'evenement?.
D'un les objets prevoient de gerer les evenements connus, la roulette n'existe pas pour les premières versions de datagrid, et de deux on peut decider faire le track sur un Hwnd quelconque. En principe si vous avez un datagrid à l'interieur d'un form avec plusieurs autres objets, la molette devrait intelligemment agir sur le datagrid, activé ou pas s'il s'agit su seul objet grid.
On peut vouloir tracker les evenements sur une appli externe (à ce sujet j'ai rajouté la fonction "GetWindowHwnd(ByVal plClassName As String, ByVal plWindowName As String) As Long") et pouvoir intereargir avec celle ci au moyen de la fonction "SendEventToWindow(plHwnd as long, pluMsg as long, ByVal pwParam As Long, ByVal plParam As Long). Sur cette forme la fonction SendEventToWindow est un peu du chinois à moins d'être documenté. On peut la decomposer en plusieurs fonctions plus explicites.
La reception des evenements pourrait se faire sous la forme SNA_TrackEvent( ByVal hwnd As Long, ByVal uMsg As Long, ByVal wParam As Long, ByVal lParam As Long) qui est aussi du chinois, mais le mieux serait de la decomposer en plusieurs evenements (SNA_TrackWheel, SNA_TrackKeyBoard, SNA_TrackMouse, ...) et ne reserver le SNA_TrackEvent que pour les evenements non traités.
je profite pour preciser que le detournement d'evenement se fait toujours avant d'appeler la procédure normale. Ceci permet d'annuler/transformer l'action pour les autres en fonction de ce que l'on souhaite.
Merci encore Vbfrance de ce que j'ai pu apprendre et cette ouverture sur ce monde merveilleux du Subclassing et divers grace a vous multiples sources que je parcoure regulièrement. Nix, u r de best.
Vous n'êtes pas encore membre ?
inscrivez-vous, c'est gratuit et ça prend moins d'une minute !
Les membres obtiennent plus de réponses que les utilisateurs anonymes.
Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes et codes sources.
Le fait d'être membre vous permet d'avoir des options supplémentaires.