Подскажите пожалуйста, как сделать, чтобы строки в ListBox можно было мышкой перетащить выше или ниже?
Понимаю, что нужно копать в сторону OLEDragMod, но что дальше?
Option Explicit
Private Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hWnd As Long, ByVal wMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
Private Const LB_ITEMFROMPOINT = &H1A9&
Dim SourceIndex As Long, hLst As Long
Private Sub Form_Load()
list1.OLEDropMode = vbOLEDropManual
list1.OLEDragMode = vbOLEDragAutomatic
With lblK
.AutoSize = True
.Caption = "> "
.Visible = False
.Move list1.Left - .Width
End With
Dim i As Integer
For i = 0 To 100
list1.AddItem "kkkkkkk " & i
Next
End Sub
Private Sub List1_OLEDragDrop(Data As DataObject, Effect As Long, Button As Integer, Shift As Integer, X As Single, Y As Single)
Dim s As String, DestIndex As Long
If Data.GetFormat(vbCFText) Then
s = Data.GetData(vbCFText)
DestIndex = SendMessage(list1.hWnd, LB_ITEMFROMPOINT, 0, 65536 * (Y \ Screen.TwipsPerPixelY) + (X \ Screen.TwipsPerPixelX))
If (SourceIndex <> DestIndex) And ((DestIndex And &HFFFF0000) = 0) Then
If SourceIndex > DestIndex Then
list1.AddItem list1.List(SourceIndex), DestIndex
SourceIndex = SourceIndex + 1
Else
list1.AddItem list1.List(SourceIndex), DestIndex + 1
End If
list1.RemoveItem SourceIndex
SourceIndex = DestIndex
list1.ListIndex = DestIndex
End If
End If
lblK.Visible = False
End Sub
Private Sub List1_OLEDragOver(Data As DataObject, Effect As Long, Button As Integer, Shift As Integer, X As Single, Y As Single, State As Integer)
If Data.GetFormat(vbCFText) Then
If Y Then lblK.Top = Y + list1.Top
Select Case Y
Case 0
Case Is <= 100
If list1.TopIndex Then list1.TopIndex = list1.TopIndex - 1
Case Is >= list1.Height - 100 - lblK.Height
list1.TopIndex = list1.TopIndex + 1
End Select
Else
Effect = vbDropEffectNone
End If
End Sub
Private Sub list1_OLEStartDrag(Data As DataObject, AllowedEffects As Long)
lblK.Visible = True
AllowedEffects = vbDropEffectMove
SourceIndex = list1.ListIndex
End Sub
Ещё надо бы как-то проверить, что перетаскивается не что-то вообще, а именно строка из этого же самого списка.
Option Explicit
'Эмуляция таскания мишью пунктов листбокса
Private Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hWnd As Long, ByVal wMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
Private Const LB_ITEMFROMPOINT = &H1A9&
Dim SourceIndex As Long, hLst As Long
Private Sub Form_Click() 'просто чтобы заполнить список сильнее - чтобы появилась прокрутка
Form_Load
End Sub
Private Sub Form_Load()
list1.OLEDropMode = vbOLEDropManual
list1.OLEDragMode = vbOLEDragAutomatic
Set lblK.Font = list1.Font
With lblK
.AutoSize = True
.Caption = ">"
.Visible = False
.Move list1.Left - .Width
hLst = .Height \ 2 ' вполне хватает и половины высоты списка
End With
Dim i As Integer
For i = 0 To 5 ' заполняю лист, чтобы было что таскать
list1.AddItem "kkkkkkk " & i
Next
SourceIndex = -2
End Sub
Private Sub list1_OLECompleteDrag(Effect As Long)
lblK.Visible = False
SourceIndex = -2 ' выставляю заведомо невозможное для листинлекса значение
End Sub
Private Sub List1_OLEDragDrop(Data As DataObject, Effect As Long, Button As Integer, Shift As Integer, X As Single, Y As Single)
Dim s As String, DestIndex As Long
If Y < 0 Then Exit Sub
If SourceIndex = -2 Then
' здесь можно написать код того случая,
' когда что-то в список притащено не из самого списка, а снаружи
'If Data.GetFormat(vbCFText) Then
' s = Data.GetData(vbCFText)
'End If
Exit Sub
End If
DestIndex = SendMessage(list1.hWnd, LB_ITEMFROMPOINT, 0, 65536 * (Y \ Screen.TwipsPerPixelY) + (X \ Screen.TwipsPerPixelX))
If (DestIndex And &HFFFF0000) Then DestIndex = list1.ListCount - 1 ' это произходит,
' если пункт утащен ниже последней строки, поэтому и берём последнюю строку
If (SourceIndex <> DestIndex) And ((DestIndex And &HFFFF0000) = 0) Then
If SourceIndex > DestIndex Then
list1.AddItem list1.List(SourceIndex), DestIndex
SourceIndex = SourceIndex + 1
Else
list1.AddItem list1.List(SourceIndex), DestIndex + 1
End If
list1.RemoveItem SourceIndex
SourceIndex = DestIndex
list1.ListIndex = DestIndex
'вообще-то, здесь нужно уравнять ещё и свойства "перемещённой" строки:
'.ItemData() ,а если стиль установлен с чекбоксами, то и .Selected()
End If
End Sub
Private Sub List1_OLEDragOver(Data As DataObject, Effect As Long, Button As Integer, Shift As Integer, X As Single, Y As Single, State As Integer)
' If Data.GetFormat(vbCFText) Then
If SourceIndex > -2 Then
If Y Then lblK.Top = Y + list1.Top
Select Case Y
Case 0
Case Is < hLst
If list1.TopIndex Then list1.TopIndex = list1.TopIndex - 1
Case Is > list1.Height - hLst - lblK.Height
list1.TopIndex = list1.TopIndex + 1
End Select
Else
Effect = vbDropEffectNone
' но можно и разрешить - если нужна возможность добавлять в список что-то снаружи
End If
End Sub
Private Sub list1_OLEStartDrag(Data As DataObject, AllowedEffects As Long)
'это событие произойдёт, если тащим именно строку самого списка
lblK.Visible = True
AllowedEffects = vbDropEffectMove '
SourceIndex = list1.ListIndex
'если же тащим что-то снаружи,AllowedEffects останется vbDropEffectCopy,
'а SourceIndex останется -2 , то есть в событии _OLEDragDrop можно будет узнать,
'снаружи данные, или из самого списка
End Sub
Сейчас этот форум просматривают: Google-бот и гости: 31