Empêcher le déplacement des items d'un listview

Description

Ce code permet d'empêcher l'utilisateur de déplacer les items à l'intérieur d'un listview vu que VB ne donne pas de propriété pour le faire...

Un message de notification WM_NOTIFY est envoyé avec un LVN_BEGINDRAG à la fenêtre propriétaire du listview. En interceptant ce message et en l'empêchant de parvenir à la fenêtre, on peut empêcher le déplacement des items dans le listview.

Ce code utilise le Subclassing : aussi est il impératif de fermer l'application par la croix de la fenêtre principale et non par le bouton Stop de VB...sinon GENERAL PROTECTION FAULT...De plus, tout subclassing doit être impérativement enlevé avant la fin du programme (Form_Unload)...sinon idem...

Ce code s'inspire de http://www.devx.com/vb2themax/Tip/18444...
Je précise que ce n'est pas un copier-coller...

Source / Exemple :


Option Explicit

'message de notification pour une fenêtre
Private Const WM_NOTIFY As Long = &H4E

'premier sous message de notification
Private Const LVN_FIRST As Long = -100
'début d'un déplacement bouton gauche sur un ListView
Private Const LVN_BEGINDRAG As Long = (LVN_FIRST - 9)
'début d'un déplacement bouton droit sur un ListView
Private Const LVN_BEGINRDRAG As Long = (LVN_FIRST - 11)
'début d'un défilement sur un ListView
Private Const LVN_BEGINSCROLL As Long = (LVN_FIRST - 80)
'fin d'un défilement sur un ListView
Private Const LVN_ENDSCROLL As Long = (LVN_FIRST - 81)

'fonction de fenêtre pour une fenêtre
Private Const GWL_WNDPROC As Long = -4
'renvoie une des valeurs associées à une fenêtre
Private Declare Function GetWindowLong Lib "user32.dll" Alias "GetWindowLongA" (ByVal hWnd As Long, ByVal nIndex As Long) As Long
'modifie une des valeurs associées à une fenêtre
Private Declare Function SetWindowLong Lib "user32.dll" Alias "SetWindowLongA" (ByVal hWnd As Long, ByVal nIndex As Long, ByVal dwNewLong As Long) As Long
'appel une procédure de fenêtre
Private Declare Function CallWindowProc Lib "user32.dll" Alias "CallWindowProcA" (ByVal lpPrevWndFunc As Long, ByVal hWnd As Long, ByVal msg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long

'copie une zone de mémoire dans une autre
Private Declare Sub CopyMemory Lib "kernel32.dll" Alias "RtlMoveMemory" (ByRef Destination As Any, ByRef Source As Any, ByVal Length As Long)

'entête d'un message de notification (dans lParam)
Private Type NMHDR
    hwndFrom As Long    'handle de la fenêtre émettrice
    idfrom As Long      'id du contrôle
    code As Long        'code de notification
End Type
Dim lpPrevWnd As Long   'adresse de la procédure de fenêtre avant le hook

'installe un espion sur la fenêtre spécifiée
'===================================
'hWnd : handle de la fenêtre que l'on veux espionner
'bHook : indique si l'on doit ajouter (True) ou supprimer(False) l'espion de la fenêtre
Public Function SubclassWnd(hWnd As Long, bHook As Boolean) As Long
    'si on doit ajouter l'espion
    If bHook Then
        's'il n'y est pas déjà
        If lpPrevWnd = 0 Then
            'on l'ajoute avec SetWindowLong
            lpPrevWnd = SetWindowLong(hWnd, GWL_WNDPROC, AddressOf WindowProc)
            'on enregistre l'adresse précédente
            SubclassWnd = lpPrevWnd
        Else
            'sinon rien à faire
            SubclassWnd = 0
        End If
    'sinon
    Else
        'si la fenêtre est espionnée
        If lpPrevWnd Then
            'on retire l'espion avec SetWindowLong
            SubclassWnd = SetWindowLong(hWnd, GWL_WNDPROC, lpPrevWnd)
            lpPrevWnd = 0
        Else
            'sinon rien à faire
            SubclassWnd = 0
        End If
    End If
End Function

'procédure espionne de la fenêtre
'=====================================
'hWnd : handle de la fenêtre qui reçoit ce message
'uMsg : message reçu
'wParam : paramètre pour ce message
'lParam : paramètre pour ce message
Public Function WindowProc(ByVal hWnd As Long, ByVal uMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
    'si ce message est un message de notification
    If uMsg = WM_NOTIFY Then
        'on utilise une structure NMHDR pour plus d'infos sur le message
        Dim nmNotify As NMHDR
        
        'on copie le NMLISTVIEW et donc le NMHDR contenu dans la zone mémoire pointée par lParam
        CopyMemory nmNotify, ByVal lParam, Len(nmNotify)
        'si ce message est un message de déplacement dans un listview
        If nmNotify.code = LVN_BEGINDRAG Then
            'on l'élimine
            WindowProc = 1
            Exit Function
        End If
    End If
    'sinon, on passe le message à la fenêtre visée
    WindowProc = CallWindowProc(lpPrevWnd, hWnd, uMsg, wParam, lParam)
End Function

Conclusion :


Le code est commenté...

N'hésitez pas à commenter et à noter...

Codes Sources

A voir également

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.