Very Cool DragListBox that enables the user to move Items from one Position to another !

Jaafar Tribak

Well-known Member
Joined
Dec 5, 2002
Messages
9,779
Office Version
  1. 2016
Platform
  1. Windows
WorkBook example.

Hi all.

I have been working hard on this one and hopefully ,at last, I seem to have achieved some nice results :

DragList-1.jpg


Basically, the code creates a real ListBox Control from scratch and subclass it to make it a Drag listbox and to capture other events as well. All done in VBA !

The Class also defines some common Properties and Methods for easy use.

Class Code (CListBox)

Code:
'// Class that creates a Drag ListBox
'// and define other custom Properties,
'// Methods and Events.
'// All done in VBA !
 
Option Explicit
 
Public Event MouseMove(ByVal X As Long, ByVal Y As Long)
Public Event Change(ByVal ItemValue As String)
Public Event DBLClick()
Public Event Click()
 
Private Type LOGBRUSH
    lbStyle As Long
    lbColor As Long
    lbHatch As Long
End Type
 
Private Type RECT
    Left As Long
    Top As Long
    Right As Long
    Bottom As Long
End Type
 
Private Type POINTAPI
    X As Long
    Y As Long
End Type
 
Private Type DRAGLISTINFO
    uNotification As Long
    hwnd As Long
    ptCursor As POINTAPI
End Type
 
Private Declare Function FindWindow Lib "user32" _
Alias "FindWindowA" _
(ByVal lpClassName As String, _
ByVal lpWindowName As String) As Long
 
Private Declare Function GetWindow Lib "user32.dll" _
(ByVal hwnd As Long, _
ByVal wCmd As Long) As Long
 
Private Declare Function RegisterWindowMessage Lib "user32" _
Alias "RegisterWindowMessageA" _
(ByVal lpString As String) As Long
 
Private Declare Function MakeDragList Lib "comctl32" _
(ByVal hLB As Long) As Boolean
 
Private Declare Sub DrawInsert Lib "comctl32" _
(ByVal handParent As Long, _
ByVal hLB As Long, ByVal nItem As Long)
 
Private Declare Function LBItemFromPt Lib "comctl32" _
(ByVal hLB As Long, ByVal X As Long, ByVal Y As Long, _
ByVal bAutoScroll As Boolean) As Long
 
Private Declare Sub CopyMemory Lib "kernel32.dll" _
Alias "RtlMoveMemory" _
(ByRef Destination As Any, _
ByRef Source As Any, _
ByVal Length As Long)
 
Private Declare Function CreateWindowEx Lib "user32" _
Alias "CreateWindowExA" _
(ByVal dwExStyle As Long, _
ByVal lpClassName As String, _
ByVal lpWindowName As String, _
ByVal dwStyle As Long, _
ByVal X As Long, _
ByVal Y As Long, _
ByVal nWidth As Long, _
ByVal nHeight As Long, _
ByVal hWndParent As Long, _
ByVal hMenu As Long, _
ByVal hInstance As Long, _
lpParam As Any) As Long
 
Private Declare Function DestroyWindow Lib "user32" _
(ByVal hwnd As Long) As Long
 
Private Declare Function SetWindowLong Lib "user32" _
Alias "SetWindowLongA" _
(ByVal hwnd As Long, ByVal nIndex As Long, _
ByVal dwNewLong As Long) As Long
 
Private Declare Function CallWindowProc Lib "user32" _
Alias "CallWindowProcA" _
(ByVal lpPrevWndFunc As Long, ByVal hwnd As Long, _
ByVal MSG As Long, ByVal wParam As Long, _
ByVal lParam As Long) As Long
 
Private Declare Function SendMessage Lib "user32.dll" _
Alias "SendMessageA" _
(ByVal hwnd As Long, ByVal wMsg As Long, _
ByVal wParam As Long, ByRef lParam As Any) As Long
 
Private Declare Function SetCursor Lib "user32" _
(ByVal hCursor As Long) As Long
 
Private Declare Function LoadCursorFromFile Lib "user32" _
Alias "LoadCursorFromFileA" _
(ByVal lpFileName As String) As Long
 
Private Declare Function GetCursorPos Lib "user32.dll" _
(ByRef lpPoint As POINTAPI) As Long
 
Private Declare Function ScreenToClient Lib "user32.dll" _
(ByVal hwnd As Long, ByRef lpPoint As POINTAPI) As Long
 
Private Declare Function GetDC Lib "user32" _
(ByVal hwnd As Long) As Long
 
Private Declare Function GetDeviceCaps Lib "gdi32" _
(ByVal hDc As Long, ByVal _
nIndex As Long) As Long
Private Declare Function ReleaseDC Lib "user32" _
(ByVal hwnd As Long, ByVal _
hDc As Long) As Long
 
Private Declare Function SetFocus Lib "user32.dll" _
(ByVal hwnd As Long) As Long
 
Private Declare Function SetBkMode Lib "gdi32" _
(ByVal hDc As Long, ByVal nBkMode As Long) As Long
 
Private Declare Function CreateBrushIndirect Lib "gdi32" _
(lpLogBrush As LOGBRUSH) As Long
 
Private Declare Function FillRect Lib "user32" _
(ByVal hDc As Long, lpRect As RECT, _
ByVal hBrush As Long) As Long
 
Private Declare Function GetClientRect Lib "user32" _
(ByVal hwnd As Long, lpRect As RECT) As Long
 
Private Declare Function DeleteObject Lib "gdi32" _
(ByVal hObject As Long) As Long
 
Private Declare Function SetTextColor Lib "gdi32" _
(ByVal hDc As Long, ByVal crColor As Long) As Long
 
Private Declare Function InvalidateRect Lib "user32.dll" _
(ByVal hwnd As Long, _
ByVal lpRect As Long, _
ByVal bErase As Long) As Long
 
Private Const WM_USER = &H400
Private Const DL_BEGINDRAG = (WM_USER + 133)
Private Const DL_DRAGGING = (WM_USER + 134)
Private Const DL_DROPPED = (WM_USER + 135)
Private Const DL_CANCELDRAG = (WM_USER + 136)
Private Const DRAGLISTMSGSTRING = "commctrl_DragListMsg"
 
Private Const LB_GETCURSEL = &H188
Private Const LB_DELETESTRING = &H182
Private Const LB_ADDSTRING = &H180
Private Const LB_INSERTSTRING = &H181
Private Const LB_GETTEXT = &H189
Private Const LB_GETTEXTLEN = &H18A
Private Const LB_GETTOPINDEX = &H18E
Private Const LB_GETCOUNT = &H18B
Private Const LB_RESETCONTENT = &H184
Private Const LB_SETCURSEL = &H186
 
Private Const WS_EX_CLIENTEDGE = &H200&
Private Const LBS_HASSTRINGS = &H40&
Private Const LBS_NOTIFY = &H1&
Private Const WS_CHILD = &H40000000
Private Const WS_VISIBLE = &H10000000
Private Const WS_VSCROLL = &H200000
Private Const LB_Styles = _
(LBS_HASSTRINGS Or LBS_NOTIFY Or WS_CHILD _
Or WS_VISIBLE Or WS_VSCROLL)
 
Private Const WM_COMMAND = &H111
Private Const WM_PARENTNOTIFY = &H210
Private Const WM_CTLCOLORLISTBOX = &H134
Private Const WM_PAINT = &HF
Private Const WM_SETCURSOR = &H20
Private Const LBN_SELCHANGE = 1
Private Const LBN_DBLCLK = 2
Private Const WM_KEYDOWN = &H100
Private Const WM_KEYUP = &H101
Private Const WM_MOUSEMOVE = &H200
Private Const WM_LBUTTONDOWN = &H201
Private Const WM_DESTROY = &H2
Private Const GWL_WNDPROC = (-4)
Private Const GW_CHILD = 5
 
Private Const LOGPIXELSX = 88
Private Const LOGPIXELSY = 90
 
Private Const CurFile As String = "\Drag.Cur"
Private bHookSet As Boolean
Private bDragList As Boolean
Private DragIdx As Long
Private DL_Message As Long
Private lBackColor As Long
Private lTextColor As Long
Private sLBItemText As String
 
'===================
'Private Routines.
'===================
Private Sub Class_Initialize()
 
    Set oLB = Nothing
    Set oLB = Me
 
End Sub
 
Private Sub GetHiLoword _
(lParam As Long, ByRef loword As Long, ByRef hiword As Long)
 
   ' this is the LOWORD of the lParam:
    loword = lParam And &HFFFF&
    ' LOWORD now equals 65,535 or &HFFFF
    ' this is the HIWORD of the lParam:
    hiword = lParam \ &H10000 And &HFFFF&
    ' HIWORD now equals 30,583 or &H7777
 
End Sub
 
Private Property Get PointsPerPixelX() As Double
 
    Dim hDc As Long
    hDc = GetDC(0)
    PointsPerPixelX = 72 / GetDeviceCaps(hDc, LOGPIXELSX)
    ReleaseDC 0, hDc
 
End Property
 
Private Property Get PointsPerPixelY() As Double
 
    Dim hDc As Long
    hDc = GetDC(0)
    PointsPerPixelY = 72 / GetDeviceCaps(hDc, LOGPIXELSY)
    ReleaseDC 0, hDc
 
End Property
 
Private Sub CreateDragCursor()
 
    Dim lPos As Long
    Dim bData1() As Variant
    Dim bData2() As Variant
 
    '// Load the Drag cursor Bytes into 2 Var Arrays.
    bData1 = Array(0, 0, 2, 0, 1, 0, 32, 32, 16, 0, 0, 0, 0, 0, 232, 2, 0, 0, _
    22, 0, 0, 0, 40, 0, 0, 0, 32, 0, 0, 0, 64, 0, 0, 0, 1, 0, 4, 0, 0, 0, 0, _
    0, 128, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, _
    0, 0, 0, 128, 0, 0, 128, 0, 0, 0, 128, 128, 0, 128, 0, 0, 0, 128, 0, _
    128, 0, 128, 128, 0, 0, 192, 192, 192, 0, 128, 128, 128, 0, 0, 0, _
    255, 0, 0, 255, 0, 0, 0, 255, 255, 0, 255, 0, 0, 0, 255, 0, 255, 0, _
    255, 255, 0, 0, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, _
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, _
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, _
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, _
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, _
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, _
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, _
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, _
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, _
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 240)
 
    bData2 = Array(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 240, _
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 0, 0, 0, 0, 0, 0, 0, 0, _
    0, 0, 0, 0, 0, 0, 0, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, _
    240, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 0, 15, 240, 0, 0, 0, 0, _
    0, 0, 0, 0, 0, 0, 0, 0, 15, 240, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, _
    0, 0, 15, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 255, _
    255, 255, 240, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 255, 255, 255, 0, _
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 255, 255, 240, 0, 0, 0, 0, 0, 0, _
    0, 0, 0, 0, 0, 0, 15, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, _
    15, 255, 240, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 255, 0, 0, 0, _
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 240, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, _
    0, 0, 0, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, _
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, _
    0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 234, 170, 191, 255, _
    245, 85, 127, 255, 239, 255, 191, 255, 247, 255, 127, 255, 239, _
    255, 191, 255, 247, 255, 127, 255, 239, 255, 191, 255, 247, 255, _
    127, 255, 239, 255, 191, 255, 245, 85, 127, 255, 234, 170, 191, _
    254, 127, 255, 255, 252, 63, 255, 255, 252, 63, 255, 255, 248, _
    127, 255, 255, 120, 127, 255, 255, 48, 255, 255, 255, 16, 255, _
    255, 255, 1, 255, 255, 255, 0, 31, 255, 255, 0, 63, 255, 255, _
    0, 127, 255, 255, 0, 255, 255, 255, 1, 255, 255, 255, 3, 255, _
    255, 255, 7, 255, 255, 255, 15, 255, 255, 255, 31, 255, 255, _
    255, 63, 255, 255, 255, 127, 255, 255, 255, 255)
 
    '- Join the arrays
    lPos = UBound(bData1)
    ReDim Preserve bData1(UBound(bData1) + UBound(bData2))
    CopyMemory ByVal VarPtr(bData1(lPos + 1)), _
    ByVal VarPtr(bData2(0)), 16 * (UBound(bData2))
 
    '//Save the joined Array data to disk.
    SaveCurToDisk ByVal bData1
 
End Sub
 
Private Sub SaveCurToDisk(ByVal Ar As Variant)
 
    Dim X As Long
    Dim FileNum As Long
    Dim bytes() As Byte
 
    ReDim bytes(LBound(Ar) To UBound(Ar))
 
    For X = LBound(Ar) To UBound(Ar)
        bytes(X) = CByte((Ar(X)))
    Next
 
    FileNum = FreeFile
    Open Environ("Temp") & CurFile For Binary As #FileNum
    Put #FileNum, 1, bytes
    Close FileNum
 
End Sub
 
'=================================================
'Public Routines. (ListBox Properties and Methods.)
'=================================================
 
Public Function WinProc _
(ByVal hwnd As Long, ByVal uMsg As Long, _
ByVal wParam As Long, ByVal lParam As Long) As Long
 
    Dim tPt As POINTAPI
    Dim DLI As DRAGLISTINFO
    Dim LB As LOGBRUSH
    Dim tRect As RECT
 
    Dim sBuffer As String
    Dim CurSel As Long
    Dim lRet As Long
    Dim TopIndex As Long
    Dim loword As Long
    Dim hiword As Long
    Dim hBrush As Long
    Dim hDc As Long
 
 
    '// Ignore errors.
    On Error Resume Next
 
    Select Case uMsg
 
        Case WM_CTLCOLORLISTBOX '// Paint the ListBox.
 
            If lBackColor = 0 Then lBackColor = vbWhite
                LB.lbColor = lBackColor
                hBrush = CreateBrushIndirect(LB)
                GetClientRect lParam, tRect
                SetBkMode wParam, 1
                FillRect wParam, tRect, hBrush
                SetTextColor wParam, lTextColor
                WinProc = hBrush
                DeleteObject hBrush
            Exit Function
 
        Case WM_SETCURSOR '// Catch the ListBox Mouse Events.
 
            GetHiLoword lParam, loword, hiword
            If wParam = LBhwnd Then
                If hiword = WM_MOUSEMOVE Then
                    GetCursorPos tPt
                    ScreenToClient wParam, tPt
                    RaiseEvent MouseMove _
                    (tPt.X, tPt.Y)
                End If
                If hiword = WM_LBUTTONDOWN Then
                    RaiseEvent Click
                End If
            End If
 
        Case WM_PARENTNOTIFY
 
            GetHiLoword wParam, loword, hiword
            If loword = WM_DESTROY Then
                SetWindowLong hwnd, GWL_WNDPROC, PrevProc
                PrevProc = 0
                bHookSet = False
            End If
 
        Case WM_KEYUP, WM_KEYDOWN '//set KBrd focus to
 
            SetFocus LBhwnd
 
        Case WM_COMMAND '//Catch the DBLCLK and Change events.
 
            hDc = GetDC(LBhwnd)
            SendMessage LBhwnd, WM_PAINT, hDc, 0
            ReleaseDC LBhwnd, hDc
            GetHiLoword wParam, loword, hiword
            If hiword = LBN_DBLCLK Then
                RaiseEvent DBLClick
            End If
 
            If hiword = LBN_SELCHANGE Then
                CurSel = SendMessage _
                (LBhwnd, LB_GETCURSEL, 0, 0)
                lRet = SendMessage _
                (LBhwnd, LB_GETTEXTLEN, CurSel, ByVal 0)
                sBuffer = Space(lRet) & vbNullChar
                lRet = SendMessage _
                (LBhwnd, LB_GETTEXT, CurSel, ByVal sBuffer)
                sLBItemText = Left((sBuffer), lRet)
                RaiseEvent Change(ByVal sBuffer)
            End If
 
        Case DL_Message '//Process the Dragging operation.
 
            If bDragList Then
 
                CopyMemory DLI, ByVal lParam, Len(DLI)
 
                Select Case DLI.uNotification
 
                    Case DL_BEGINDRAG
 
                        '// The drag operation starts.
                        ' Return False to cancel
                        ' The item is being dragged
                        CurSel = _
                        SendMessage(DLI.hwnd, LB_GETCURSEL, 0, 0)
                        '// Get the selected item.
                        DragIdx = _
                        LBItemFromPt(DLI.hwnd, DLI.ptCursor.X, DLI.ptCursor.Y, False)
                        lRet = SendMessage(DLI.hwnd, LB_GETTEXTLEN, DragIdx, ByVal 0)
                        sBuffer = Space(lRet) & vbNullChar
                        lRet = _
                        SendMessage(DLI.hwnd, LB_GETTEXT, DragIdx, ByVal sBuffer)
                        sLBItemText = sBuffer
                        '// Continue with the drag.
                        WinProc = True
 
                    Case DL_DRAGGING
 
                        TopIndex = _
                        SendMessage(DLI.hwnd, LB_GETTOPINDEX, 0, 0)
                        '// Draw the insert icon.
                        DrawInsert lFrmChildHwnd, DLI.hwnd, _
                        LBItemFromPt(DLI.hwnd, DLI.ptCursor.X, DLI.ptCursor.Y, True)
                        SetCursor LoadCursorFromFile(Environ("Temp") & CurFile)
                        WinProc = 0
 
                    Case DL_DROPPED
 
                        SetCursor 0
                        If LBItemFromPt _
                        (DLI.hwnd, DLI.ptCursor.X, DLI.ptCursor.Y, True) _
                        <> DragIdx Then
                            If (sLBItemText) <> "" Then
                                SendMessage DLI.hwnd, LB_INSERTSTRING, _
                                LBItemFromPt _
                                (DLI.hwnd, DLI.ptCursor.X, DLI.ptCursor.Y, True) _
                                + TopIndex, ByVal sLBItemText
                                Call SendMessage _
                                (DLI.hwnd, LB_DELETESTRING, _
                                SendMessage(DLI.hwnd, LB_GETCURSEL, 0, 0), 0)
                            End If
                        End If
 
                    End Select
            End If '// IF bDragList.
 
            Exit Function
 
    End Select '// uMsg.
    WinProc = CallWindowProc _
    (PrevProc, hwnd, uMsg, wParam, lParam)
 
End Function
 
Public Sub AddItem(Item As String)
 
    SendMessage LBhwnd, LB_ADDSTRING, 0, ByVal Item
 
End Sub
 
Public Property Let BackColor(ByVal Color As Long)
 
    Dim hDc As Long
 
    lBackColor = Color
    hDc = GetDC(LBhwnd)
    SendMessage LBhwnd, WM_PAINT, hDc, 0
    ReleaseDC LBhwnd, hDc
 
End Property
 
Public Property Let TextColor(ByVal Color As Long)
 
    Dim hDc As Long
 
    lTextColor = Color
    hDc = GetDC(LBhwnd)
    SendMessage LBhwnd, WM_PAINT, hDc, 0
    ReleaseDC LBhwnd, hDc
 
End Property
 
Public Sub Clear()
 
    SendMessage LBhwnd, LB_RESETCONTENT, 0, 0
    DragIdx = 0
    sLBItemText = ""
 
End Sub
 
Public Sub Create _
(X As Single, Y As Single, W As Single, H As Single, _
ParentForm As Object)
 
    If bHookSet Then Exit Sub
 
    '// Assume the Dragging prop is set to false.
    bDragList = False
 
    lLBParentHwnd = _
    FindWindow(vbNullString, ParentForm.Caption)
    lFrmChildHwnd = GetWindow(lLBParentHwnd, GW_CHILD)
 
    '//Convert coordinates to Pixels.
    X = X / PointsPerPixelX
    Y = Y / PointsPerPixelY
    W = W / PointsPerPixelX
    H = H / PointsPerPixelY
 
    '//Create the Drag ListBox here.
    LBhwnd = CreateWindowEx(WS_EX_CLIENTEDGE, "ListBox", _
    vbNullString, LB_Styles, X, Y, W, H _
    , lFrmChildHwnd, 0, 0, 0)
 
    '//Subclass the Parent of the ListBox
    'so we can receive drag notifications.
    'and other events.
 
    DL_Message = RegisterWindowMessage(DRAGLISTMSGSTRING)
    MakeDragList LBhwnd
    PrevProc = SetWindowLong _
    (lFrmChildHwnd, GWL_WNDPROC, AddressOf TransitProc)
 
    If PrevProc <> 0 Then bHookSet = True
 
    '//create the Drag Cursor.
    Call CreateDragCursor
 
End Sub
 
Public Sub Destroy()
 
    '//CleanUp.
    DestroyWindow LBhwnd
    lBackColor = 0
    lTextColor = 0
    Kill Environ("Temp") & CurFile
 
End Sub
 
Public Property Let DragList(ByVal Value As Boolean)
 
    If Value Then bDragList = True Else bDragList = False
    '//Refresh the form screen.
    InvalidateRect lFrmChildHwnd, 0, 0
 
End Property
 
Public Property Get DragList() As Boolean
 
    DragList = bDragList
 
End Property
 
Public Property Get GetCount() As Long
 
    GetCount = SendMessage(LBhwnd, LB_GETCOUNT, 0, 0)
 
End Property
 
Public Function GetItem(Index As Long) As String
 
    Dim sBuffer As String
    Dim lRet As Long
 
    On Error Resume Next
 
    lRet = SendMessage(LBhwnd, LB_GETTEXTLEN, Index, ByVal 0)
    sBuffer = Space(lRet) & vbNullChar
    lRet = SendMessage(LBhwnd, LB_GETTEXT, Index, ByVal sBuffer)
    GetItem = sBuffer
 
End Function
 
Public Property Get Index() As Long
 
    Index = SendMessage(LBhwnd, LB_GETCURSEL, 0, 0)
 
End Property
 
Public Sub RemoveItem(Index As Long)
 
     SendMessage LBhwnd, LB_DELETESTRING, Index, 0
 
End Sub
 
Public Property Get TopIndex() As Long
 
    TopIndex = SendMessage(LBhwnd, LB_GETTOPINDEX, 0, 0)
 
End Property
 
Public Property Get Value() As String
 
    Dim sBuffer As String
    Dim lRet As Long
    Dim lIndex As Long
 
    On Error Resume Next
 
    lIndex = SendMessage(LBhwnd, LB_GETCURSEL, 0, 0)
    lRet = SendMessage(LBhwnd, LB_GETTEXTLEN, lIndex, ByVal 0)
    sBuffer = Space(lRet) & vbNullChar
    lRet = SendMessage(LBhwnd, LB_GETTEXT, lIndex, ByVal sBuffer)
    Value = sBuffer
 
End Property
 
Public Sub SlelectItem(Index As Long)
 
    Dim hDc As Long
 
    SendMessage LBhwnd, LB_SETCURSEL, Index, 0
    hDc = GetDC(LBhwnd)
    SendMessage LBhwnd, WM_PAINT, hDc, 0
    ReleaseDC LBhwnd, hDc
 
End Sub


Code in a Standard Module :

Code:
Option Explicit
 
Public lLBParentHwnd As Long
Public lFrmChildHwnd As Long
Public LBhwnd As Long
Public PrevProc As Long
Public oLB As CListBox
 
Public Function TransitProc( _
ByVal hwnd As Long, ByVal MSG As Long, _
ByVal wParam As Long, ByVal lParam As Long) As Long
 
 
 TransitProc = CallByName _
 (oLB, "WinProc", VbMethod, hwnd, MSG, wParam, lParam)
 
 
End Function

Code in the UserForm Module ( Required Labels need to be added.)

Code:
Option Explicit
 
Private WithEvents LB As CListBox
 
'---------------------------
'// UserForm Default Events.
'---------------------------
Private Sub UserForm_Initialize()
 
    Dim i As Long
 
    '// create our Drag ListBox.
    Set LB = New CListBox
 
    With LB
        .Create 20, Label1.Top, _
        90, 150, Me
 
        '// Populate the ListBox.
        For i = 0 To 39
            .AddItem "Item:    " & CStr(i)
        Next
 
        '// Set some of its Properties.
       .AddItem "Driss Cherkaoui"
        '.BackColor = vbYellow
        .TextColor = vbRed
        .DragList = True
       If .DragList Then Me.CkBDragList = True
    End With
 
End Sub
 
Private Sub CkBDragList_Change()
 
    LB.DragList = Me.CkBDragList.Value
 
End Sub
 
Private Sub UserForm_QueryClose _
(Cancel As Integer, CloseMode As Integer)
 
    LB.Destroy
 
End Sub
 
 
'---------------------------
'// Drag ListBox Events.
'---------------------------
Private Sub LB_DBLClick()
 
    MsgBox "You Double Clicked."
 
End Sub
 
Private Sub LB_Click()
 
    '//  Do stuff here...
 
End Sub
 
Private Sub LB_Change(ByVal ItemValue As String)
 
    LblCurSel.Caption = ItemValue
    LblTopIndex.Caption = LB.TopIndex
    LblCurIndex.Caption = LB.Index
 
End Sub
 
Private Sub LB_MouseMove(ByVal X As Long, ByVal Y As Long)
 
    LblX.Caption = X
    LblY.Caption = Y
 
End Sub

One known limitation is the ListBox not getting the KeyBoard focus if another normal listBox or TextBox happen to coexist on the userform.
I am still looking into this to see if I can fix it.

Tested on Excel 2003 Win XP only. (Seems quite stable)
 
Last edited:
It isn't possible to get this off of the Box URL listed above, is there any other place to get the code in its entirety?
 
Upvote 0

Excel Facts

Lock one reference in a formula
Need 1 part of a formula to always point to the same range? use $ signs: $V$2:$Z$99 will always point to V2:Z99, even after copying
Try the link in post#9 it works for me.
 
Upvote 0

Forum statistics

Threads
1,223,275
Messages
6,171,122
Members
452,381
Latest member
Nova88

We've detected that you are using an adblocker.

We have a great community of people providing Excel help here, but the hosting costs are enormous. You can help keep this site running by allowing ads on MrExcel.com.
Allow Ads at MrExcel

Which adblocker are you using?

Disable AdBlock

Follow these easy steps to disable AdBlock

1)Click on the icon in the browser’s toolbar.
2)Click on the icon in the browser’s toolbar.
2)Click on the "Pause on this site" option.
Go back

Disable AdBlock Plus

Follow these easy steps to disable AdBlock Plus

1)Click on the icon in the browser’s toolbar.
2)Click on the toggle to disable it for "mrexcel.com".
Go back

Disable uBlock Origin

Follow these easy steps to disable uBlock Origin

1)Click on the icon in the browser’s toolbar.
2)Click on the "Power" button.
3)Click on the "Refresh" button.
Go back

Disable uBlock

Follow these easy steps to disable uBlock

1)Click on the icon in the browser’s toolbar.
2)Click on the "Power" button.
3)Click on the "Refresh" button.
Go back
Back
Top