If my post was helpful to you, then express your gratitude using Rate this Post.
And if your problem is SOLVED, then please Mark the Thread as RESOLVED (see it in action - video) My system: AMD FX 6100, Gigabyte Motherboard, 8 GB Crossair Vengance, Cooler Master 450W Thunder PSU, 1.4 TB HDD, 18.5" TFT(Wide), Antec V1 Cabinet Social Group:VBForums - Developers from India
Hotswapping (by holding with left mousebutton or ctrl + up/down key)
Code:
Option Explicit
Private WithEvents HotSwap As ListBox
Private HotSwapIndex As Integer
' sample listboxes
Private Sub Form_Load()
List1.AddItem "One"
List1.AddItem "Two"
List1.AddItem "Three"
List2.AddItem "One"
List2.AddItem "Two"
List2.AddItem "Three"
End Sub
Private Sub HotSwap_KeyDown(KeyCode As Integer, Shift As Integer)
If Shift And vbCtrlMask Then
Select Case KeyCode
Case vbKeyDown
If HotSwap.ListIndex + 1 < HotSwap.ListCount Then
HotSwapIndex = HotSwap.ListIndex
HotSwap.ListIndex = HotSwapIndex + 1
HotSwap_MouseMove vbLeftButton, 0, 0, 0
KeyCode = 0
End If
Case vbKeyUp
If HotSwap.ListIndex > 0 Then
HotSwapIndex = HotSwap.ListIndex
HotSwap.ListIndex = HotSwapIndex - 1
HotSwap_MouseMove vbLeftButton, 0, 0, 0
KeyCode = 0
End If
End Select
End If
End Sub
Private Sub HotSwap_MouseDown(Button As Integer, Shift As Integer, X As Single, Y As Single)
If Button And vbLeftButton Then HotSwapIndex = HotSwap.ListIndex
End Sub
Private Sub HotSwap_MouseMove(Button As Integer, Shift As Integer, X As Single, Y As Single)
Dim strItem As String, lngItemData As Long
If Button And vbLeftButton Then
If HotSwapIndex < 0 Then Exit Sub
If HotSwap.ListIndex < 0 Then Exit Sub
If HotSwapIndex <> HotSwap.ListIndex Then
strItem = HotSwap.List(HotSwapIndex)
lngItemData = HotSwap.ItemData(HotSwapIndex)
HotSwap.List(HotSwapIndex) = HotSwap.List(HotSwap.ListIndex)
HotSwap.ItemData(HotSwapIndex) = HotSwap.ItemData(HotSwap.ListIndex)
HotSwap.List(HotSwap.ListIndex) = strItem
HotSwap.ItemData(HotSwap.ListIndex) = lngItemData
HotSwapIndex = HotSwap.ListIndex
End If
End If
End Sub
' sample listbox
Private Sub List1_GotFocus()
Set HotSwap = List1
End Sub
Private Sub List1_LostFocus()
Set HotSwap = Nothing
End Sub
' sample listbox
Private Sub List2_GotFocus()
Set HotSwap = List2
End Sub
Private Sub List2_LostFocus()
Set HotSwap = Nothing
End Sub
Faster ArrayInitialized
Code:
' usage: If ArrayInitialized(Not Not MyArrayVariable) Then
Public Function ArrayInitialized(ByVal NotNotArray As Long) As Boolean
' this fixes an IDE bug with "Not ArrayVariable"
Debug.Assert App.hInstance
' NotNotArray = 0 = uninitialized
ArrayInitialized = NotNotArray
End Function
Faster IsList (uses Object because UserControls/ActiveX are not Controls)
Code:
Public Function IsList(Ctl As Object) As Boolean
IsList = TypeOf Ctl Is ListBox
If Not IsList Then IsList = TypeOf Ctl Is ComboBox
If Not IsList Then IsList = TypeOf Ctl Is FileListBox
End Function
Issues in cafeenman's codes in the first post:
FillArrayFromList always throws an error when executing vItemData(n) = List.ItemData(n) because after the For loop n = List.ListCount
Functions with sArray always throw an error when passing multidimensional string arrays (simple to fix by calling Erase sArray if the array is initialized)
ItemDataFromListIndex returns a Variant but ItemData is always a Long
MoveDownInList & MoveUpInList for better performance could swap the item information instead of remove + add
There is no performance problem with any of this. I'll take your word for it that some things might be faster but items swap as fast as you can click them.
I didn't take user controls into consideration because I don't make them and haven't come across one yet that I would use. But it's a simple change so not a problem to make it.
I know that itemdata is always a long. I don't remember why I made it a variant because I never ever use variants unless VB makes me. The code may have been different at one point and required a variant or may require a variant as written. Not sure because I haven't needed to update that code for years.
You might consider adding a find function (commonly asked on this forum). Using SendMessage with the following messages is extremely fast: LB_FINDSTRING, LB_FINDSTRINGEXACT, CB_FINDSTRING, CB_FINDSTRINGEXACT
Insomnia is just a byproduct of, "It can't be done"
You might consider adding a find function (commonly asked on this forum). Using SendMessage with the following messages is extremely fast: LB_FINDSTRING, LB_FINDSTRINGEXACT, CB_FINDSTRING, CB_FINDSTRINGEXACT
OK
vb Code:
Private Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hWnd As Long, ByVal wMsg As Long, ByVal wParam As Long, lParam As Any) As Long
Private Declare Function SendMessageByString& Lib "user32" Alias "SendMessageA" (ByVal hWnd As Long, ByVal wMsg As Long, ByVal wParam As Long, ByVal lParam As String)
Private Const CB_FINDSTRINGEXACT As Long = &H158
Private Const LB_FINDSTRINGEXACT As Long = &H1A2&
Private Const LB_GETHORIZONTALEXTENT = &H193
Private Const LB_ITEMFROMPOINT = &H1A9
Private Const LB_SETHORIZONTALEXTENT = &H194
Public Function FindPartialStringInArray(sArray() As String, s As String) As Long
Dim n As Long
' Returns Index if found.
' Returns -1 if error or not found.
' Strings are not case-sensitive.
On Error GoTo errHandler ' Returns Error Code.
If Not ArrayInitialized(sArray) Then
FindPartialStringInArray = -1
Exit Function
End If
For n = LBound(sArray) To UBound(sArray)
If InStr(1, sArray(n), s, vbTextCompare) Then
FindPartialStringInArray = n
Exit Function
End If
Next n
' Not found.
FindPartialStringInArray = -1
Exit Function
errHandler:
FindPartialStringInArray = -1
End Function
Public Function FindPartialStringInList(ByRef List As Control, ByVal LastIndex As Long, ByVal sString As String) As Long
Dim n As Long
Dim s As String
' Returns ListIndex if found.
' Returns -1 if not found.
' Strings are not case-sensitive.
On Error GoTo errHandler
s = LCase$(sString)
If s = vbNullString Then
' LastIndex = 0
FindPartialStringInList = -1
Exit Function
End If
With List
If .ListCount = 0 Then
' LastIndex = 0
FindPartialStringInList = -1
Exit Function
End If
For n = LastIndex To .ListCount - 1
If InStr(1, LCase$(.List(n)), s, vbTextCompare) Then
FindPartialStringInList = n
'.ListIndex = n
'LastIndex = .ListIndex + 1
'.SetFocus
'.Selected(n) = True
Exit Function
End If
Next n
MsgBox sString & " not found.", vbInformation, APP_TITLE