OLEDrag&Drop

The place for threads about TimoSoft ExplorerListView.
User avatar
TiKu
Administrator
Administrator
Posts: 832
Joined: 28 Sep 2004, 21:10
Location: München
Contact:

Re: OLEDrag&Drop

Post by TiKu »

You could try sobNumericIntValue instead of sobText. I think you can also store the numeric value in the ItemData property and sort by ItemData instead of Text. And last but not least you can use custom sorting (sobCustom). This will use an event to compare two items and so actually lets your application do the comparison.
I'm not sure whether options 1 and 2 will work as expected / are available. Option 3 will definitly work.
Crunching for Fab36_Folding-Division at Folding@Home. Join Fab36/Fab30! - Folding@Home and BOINC
Boycott DRM! Boycott HDCP!
engee30
Lt. Commander
Posts: 54
Joined: 25 Sep 2012, 19:49
Location: Swindon, UK
Contact:

Re: OLEDrag&Drop

Post by engee30 »

Oops, I'm afraid it's beyond my basic skills to actually make it work. :oops:
I tried those sobNumericIntValue and sobCustom sorting Criteria, but they did nothing.
As for accessing ItemData property and then sorting it, I haven't a clue how to do that. I've already done some research into the issue, and all I get is - no proper solution to sort items consisting of String and Numeric values in one string. Need to try harder, I guess.
If anyone is aware of such a sorting solution, or knows how to implement the ones already present in the Listview, I'd very much appreciate it.
I just hope, TiKu, that you can actually come up with a solution to my problem.

Looking forward to hearing from you.
Pete
User avatar
TiKu
Administrator
Administrator
Posts: 832
Joined: 28 Sep 2004, 21:10
Location: München
Contact:

Re: OLEDrag&Drop

Post by TiKu »

There is an event called CompareItems (or similsr). If you use sobCustom as first sorting criterion, this event will be raised to compare items during sorting. You can use this event to apply your own sorting rules. For instance you can parse the item texts, extract the numbers and compare them. The event has a ByRef parameter that you need to set to a value describing the desired order of the both items.
Crunching for Fab36_Folding-Division at Folding@Home. Join Fab36/Fab30! - Folding@Home and BOINC
Boycott DRM! Boycott HDCP!
engee30
Lt. Commander
Posts: 54
Joined: 25 Sep 2012, 19:49
Location: Swindon, UK
Contact:

Re: OLEDrag&Drop

Post by engee30 »

Oh dear. I give up. :evil:
At least I've found a solution to a standard Listview control, which is PERFECT (see the attached file). I tried to tweak it into my project, but failed to.
Oh well. Maybe next year I'll sort it out somehow.
Anyways, happy New Year Tiku and thanks for your help so far.
Pete
Attachments
listview order.zip
(3.15 KiB) Downloaded 510 times
engee30
Lt. Commander
Posts: 54
Joined: 25 Sep 2012, 19:49
Location: Swindon, UK
Contact:

Re: OLEDrag&Drop

Post by engee30 »

Hello everybody in the New Year.

There is another thing that I'm quite curious about dealing more with the Listview. This time I'm talking about Columns.SortArrow, where you can have saDown, saNone and saUp. Is it possible to display arrows showing the order in which the Listview columns are sorted? If not, is it possible to add my own ones through, say, an ImageList and attach the images from the ImageList to the Listview columns?
Pete
User avatar
TiKu
Administrator
Administrator
Posts: 832
Joined: 28 Sep 2004, 21:10
Location: München
Contact:

Re: OLEDrag&Drop

Post by TiKu »

I'm back home again (at least for 1 day) and am catching up with my e-mails...

A remark to your code from this post:
engee30 wrote:Yes, that was all about the Caret property. Many thanks Tiku. :)

The whole thing with the Drag'n'drop seems to be sorted out now.

Kind regards,
Pete

Code: Select all

Dim i, j As Long
You are aware that this makes i a Variant and only j a Long?
Also you seem to use drag'n'drop within the same control to re-order items. This should not be done like you have implemented it. You drop-highlight the item with which you'll swap positions. But to users, drop-highlighting means that the dropped data will be moved into/added to the highlighted item. You really should use an insertion mark instead.

Also your code to filter for selected items is inefficient:

Code: Select all

      aSel = -1
      For Each itm In ExLVwU.ListItems
        If itm.Selected = True Then
          aSel = aSel + 1
        End If
      Next itm
What's wrong with this code?

Code: Select all

  Dim col As ListViewItems

  Set col = ExLVwU.ListItems
  col.FilterType(FilteredPropertyConstants.fpSelected) = FilterTypeConstants.ftIncluding
  col.Filter(FilteredPropertyConstants.fpSelected) = Array(True)
  Debug.Print col.Count & " Items selected"
Additionally you're using the events in a strange way. Why do you use the ItemMouseEnter event for drag'n'drop stuff? Even if you really need the drop target's item index (seems weired to me), what's wrong with the dropTarget parameter of the OLEDragDrop event?

/Edit: Okay, I see that you insert the items before or after the drop target depending on the origin of the dragged items. This will lead to undefined behavior if the user selects e.g. items 1 and 10 and drops them over item 5. Where will the items be inserted in this case? It's difficult to tell. By using insertion marks for this kind of drag'n'drop, you would avoid such situations.
Nevertheless I've improved your code (removed hacks and performance bottlenecks). You should really consider insertion marks.
engee30 wrote:Oh dear. I give up. :evil:
At least I've found a solution to a standard Listview control, which is PERFECT (see the attached file). I tried to tweak it into my project, but failed to.
Oh well. Maybe next year I'll sort it out somehow.
Anyways, happy New Year Tiku and thanks for your help so far.
Pete
Here's how it can be done with ExplorerListView (in case items are named in the form "Item xyz"):

Code: Select all


Private Sub ExLVwU_CompareItems(ByVal FirstItem As ExLVwLibUCtl.IListViewItem, ByVal secondItem As ExLVwLibUCtl.IListViewItem, result As ExLVwLibUCtl.CompareResultConstants)
  Dim lFirstNumber As Long
  Dim lSecondNumber As Long

  lFirstNumber = ExtractIntFromText(FirstItem.Text)
  lSecondNumber = ExtractIntFromText(secondItem.Text)
  
  If lFirstNumber < lSecondNumber Then
    result = crFirstSecond
  ElseIf lFirstNumber > lSecondNumber Then
    result = crSecondFirst
  Else
    result = crEqual
  End If
End Sub

Private Sub ExLVwU_HeaderClick(ByVal column As ExLVwLibUCtl.IListViewColumn, ByVal button As Integer, ByVal shift As Integer, ByVal x As Single, ByVal y As Single, ByVal hitTestDetails As ExLVwLibUCtl.HeaderHitTestConstants)
  ExLVwU.SortItems sobCustom, sobText, sobNone
End Sub

Private Function ExtractIntFromText(ByVal s As String) As Long
  Dim i As Long
  Dim p As Long
  Dim ret As Long

  p = -1
  For i = Len(s) To 1 Step -1
    If IsNumeric(Mid$(s, i, 1)) Then
      p = i
    Else
      Exit For
    End If
  Next i
  If p >= 0 Then
    ret = CLng(Mid$(s, p))
  Else
    ret = -1
  End If

  ExtractIntFromText = ret
End Function
engee30 wrote:Hello everybody in the New Year.

There is another thing that I'm quite curious about dealing more with the Listview. This time I'm talking about Columns.SortArrow, where you can have saDown, saNone and saUp. Is it possible to display arrows showing the order in which the Listview columns are sorted? If not, is it possible to add my own ones through, say, an ImageList and attach the images from the ImageList to the Listview columns?
Pete
Have a look at the samples, some of them allow sorting by header click and they update the sort arrow accordingly. Using custom images is possible, yes.
Attachments
ExLvwDragDrop.zip
(154.66 KiB) Downloaded 519 times
Crunching for Fab36_Folding-Division at Folding@Home. Join Fab36/Fab30! - Folding@Home and BOINC
Boycott DRM! Boycott HDCP!
engee30
Lt. Commander
Posts: 54
Joined: 25 Sep 2012, 19:49
Location: Swindon, UK
Contact:

Re: OLEDrag&Drop

Post by engee30 »

TiKu wrote:I'm back home again (at least for 1 day) and am catching up with my e-mails...

A remark to your code from this post:
engee30 wrote:Yes, that was all about the Caret property. Many thanks Tiku. :)

The whole thing with the Drag'n'drop seems to be sorted out now.

Kind regards,
Pete

Code: Select all

Dim i, j As Long
You are aware that this makes i a Variant and only j a Long?
Oh yes, thanks for pointing that out to me. :idea:
TiKu wrote: Also you seem to use drag'n'drop within the same control to re-order items. This should not be done like you have implemented it. You drop-highlight the item with which you'll swap positions. But to users, drop-highlighting means that the dropped data will be moved into/added to the highlighted item. You really should use an insertion mark instead.
Well, now that I've learned something new about the insertion mark, I'm gonna use it from now on. I just didn't realize that there was something like that to be able to be used.
TiKu wrote: Also your code to filter for selected items is inefficient:

Code: Select all

      aSel = -1
      For Each itm In ExLVwU.ListItems
        If itm.Selected = True Then
          aSel = aSel + 1
        End If
      Next itm
That's another good point by you, Tiku. :idea:
TiKu wrote: What's wrong with this code?

Code: Select all

  Dim col As ListViewItems

  Set col = ExLVwU.ListItems
  col.FilterType(FilteredPropertyConstants.fpSelected) = FilterTypeConstants.ftIncluding
  col.Filter(FilteredPropertyConstants.fpSelected) = Array(True)
  Debug.Print col.Count & " Items selected"
Hm, I don't quite know - I never messed up with that code. :?
TiKu wrote: Additionally you're using the events in a strange way. Why do you use the ItemMouseEnter event for drag'n'drop stuff? Even if you really need the drop target's item index (seems weired to me), what's wrong with the dropTarget parameter of the OLEDragDrop event?

/Edit: Okay, I see that you insert the items before or after the drop target depending on the origin of the dragged items. This will lead to undefined behavior if the user selects e.g. items 1 and 10 and drops them over item 5. Where will the items be inserted in this case? It's difficult to tell. By using insertion marks for this kind of drag'n'drop, you would avoid such situations.
Yes, that had been my concern until I found a solution, the way in which it was sorted is surely strange. Now I know how to use insertion marks, which is a definite winner over my solution. :)
TiKu wrote:
engee30 wrote:Oh dear. I give up. :evil:
At least I've found a solution to a standard Listview control, which is PERFECT (see the attached file). I tried to tweak it into my project, but failed to.
Oh well. Maybe next year I'll sort it out somehow.
Anyways, happy New Year Tiku and thanks for your help so far.
Pete
Here's how it can be done with ExplorerListView (in case items are named in the form "Item xyz"):

Code: Select all


Private Sub ExLVwU_CompareItems(ByVal FirstItem As ExLVwLibUCtl.IListViewItem, ByVal secondItem As ExLVwLibUCtl.IListViewItem, result As ExLVwLibUCtl.CompareResultConstants)
  Dim lFirstNumber As Long
  Dim lSecondNumber As Long

  lFirstNumber = ExtractIntFromText(FirstItem.Text)
  lSecondNumber = ExtractIntFromText(secondItem.Text)
  
  If lFirstNumber < lSecondNumber Then
    result = crFirstSecond
  ElseIf lFirstNumber > lSecondNumber Then
    result = crSecondFirst
  Else
    result = crEqual
  End If
End Sub

Private Sub ExLVwU_HeaderClick(ByVal column As ExLVwLibUCtl.IListViewColumn, ByVal button As Integer, ByVal shift As Integer, ByVal x As Single, ByVal y As Single, ByVal hitTestDetails As ExLVwLibUCtl.HeaderHitTestConstants)
  ExLVwU.SortItems sobCustom, sobText, sobNone
End Sub

Private Function ExtractIntFromText(ByVal s As String) As Long
  Dim i As Long
  Dim p As Long
  Dim ret As Long

  p = -1
  For i = Len(s) To 1 Step -1
    If IsNumeric(Mid$(s, i, 1)) Then
      p = i
    Else
      Exit For
    End If
  Next i
  If p >= 0 Then
    ret = CLng(Mid$(s, p))
  Else
    ret = -1
  End If

  ExtractIntFromText = ret
End Function
Wow - that is magnificent! :ugeek: That's exactly what I've been after. Thanks for that, TiKu. I had to use the ColumnClick event instead, though. The HeaderClick event doesn't seem to be working with that code. Also, I added a bit of a code to make the order of the Listview changeable depending on the current SortOrder of the Listview:

Code: Select all

Private Sub ExLVwU_ColumnClick(ByVal column As ExLVwLibUCtl.IListViewColumn, ByVal button As Integer, ByVal shift As Integer, ByVal x As Single, ByVal y As Single, ByVal hitTestDetails As ExLVwLibUCtl.HeaderHitTestConstants)
ExLVwU.SortOrder = IIf((ExLVwU.SortOrder = soAscending), soDescending, soAscending)
ExLVwU.SortItems sobCustom, sobText, sobNone 'sorting works from here
End Sub
TiKu wrote:
engee30 wrote:Hello everybody in the New Year.

There is another thing that I'm quite curious about dealing more with the Listview. This time I'm talking about Columns.SortArrow, where you can have saDown, saNone and saUp. Is it possible to display arrows showing the order in which the Listview columns are sorted? If not, is it possible to add my own ones through, say, an ImageList and attach the images from the ImageList to the Listview columns?
Pete
Have a look at the samples, some of them allow sorting by header click and they update the sort arrow accordingly. Using custom images is possible, yes.
I'll definitely have a look at them for that. So far, you've been of great help to me, Tiku, and many thanks for that.
The way I got into the world of VB is through self-teaching. And as soon as I got access to the Internet, that has been my main reference book, so to speak. I'm just an amateur developer trying to build my own applications with the help of all the information I find on the Web. That's why some of my methods I use in code may seem strange to experts like you. I'm still learning, and you're proving to be a perfect source of information to me. Once again, thaks for your immense help.

I've made changes to the code im my project following your suggestions. :)

Obviously, I'll be back asking more question if I'm stuck with something.

Kind regards,
Pete
User avatar
TiKu
Administrator
Administrator
Posts: 832
Joined: 28 Sep 2004, 21:10
Location: München
Contact:

Re: OLEDrag&Drop

Post by TiKu »

engee30 wrote:I had to use the ColumnClick event instead, though.
That's even better. To use the HeaderClick event for this purpose actually isn't correct - that was a mistake in my code.
Crunching for Fab36_Folding-Division at Folding@Home. Join Fab36/Fab30! - Folding@Home and BOINC
Boycott DRM! Boycott HDCP!
engee30
Lt. Commander
Posts: 54
Joined: 25 Sep 2012, 19:49
Location: Swindon, UK
Contact:

Re: OLEDrag&Drop

Post by engee30 »

Well, I reckon I can call it a finished task. I added that SortArrow method into the code. See the attached file.
To me, one of the most efficent things about the code is the way you implemented sorting Listview items by columns. Now, you've got the natural sort instead of that artifical one, where, out of the set of "Item 1" through "Item 10", you you'll get "Item 10" just after "Item 1" (instead of "Item 2"), which is a bit of a letdown to me.
Regards,
Pete
Attachments
ExLvwDragDrop.zip
(153.83 KiB) Downloaded 487 times
engee30
Lt. Commander
Posts: 54
Joined: 25 Sep 2012, 19:49
Location: Swindon, UK
Contact:

Re: OLEDrag&Drop

Post by engee30 »

Hiya

There's something I can't get working properly. I'm talking about making a selection of a few items in a Listview via the mouse. I've got a Listview registered for OLEDrag'n'Drop. Once I left-click on a listview item, it gets dragged and dropped in the place where the mouse leaves the left-click. Is there maybe a timer to set the time before the Drag'n'Drop begins so that I can make a selection of listitems first, without firing the Drag'n'Drop? :?
Pete
User avatar
TiKu
Administrator
Administrator
Posts: 832
Joined: 28 Sep 2004, 21:10
Location: München
Contact:

Re: OLEDrag&Drop

Post by TiKu »

Set the FullRowSelect property to frsExtendedMode (Mode 2). However, this mode is only available on Windows Vista and newer, and only if you're using a manifest file so that your application loads version 6.10 (or newer) of comctl32.dll.

Regards
TiKu
Crunching for Fab36_Folding-Division at Folding@Home. Join Fab36/Fab30! - Folding@Home and BOINC
Boycott DRM! Boycott HDCP!
engee30
Lt. Commander
Posts: 54
Joined: 25 Sep 2012, 19:49
Location: Swindon, UK
Contact:

Re: OLEDrag&Drop

Post by engee30 »

Hi
Well, I tried doing what you suggested but the problem is still occuring. And only when the user starts selecting items on the item just over the space where the text is displayed. When the space is empty, I mean there's no text underneath the mouse cursor while selecting, it works like a charm (but only in the first column; in the case of other present columns, you won't be able to start selecting items - the dragging will start immediately). Quite a peculiar one to be honest. :|
User avatar
TiKu
Administrator
Administrator
Posts: 832
Joined: 28 Sep 2004, 21:10
Location: München
Contact:

Re: OLEDrag&Drop

Post by TiKu »

Well, you can also disable FullRowSelect entirely.
Crunching for Fab36_Folding-Division at Folding@Home. Join Fab36/Fab30! - Folding@Home and BOINC
Boycott DRM! Boycott HDCP!
engee30
Lt. Commander
Posts: 54
Joined: 25 Sep 2012, 19:49
Location: Swindon, UK
Contact:

Re: OLEDrag&Drop

Post by engee30 »

Hi TiKu.

I've been trying to do a Column drag, with a difference, but can't seem to be able to. I'd like to drag 3 Columns that are next to each other at the same time.

Another problem for me is to insert a new column, based on the position of the columns and not the count of the columns, between two other columns, retaining indices of the two columns. Everytime I try to insert a new column in-between, the indices change. :(

Any help much appreciated again.
Kind regards,
Pete
User avatar
TiKu
Administrator
Administrator
Posts: 832
Joined: 28 Sep 2004, 21:10
Location: München
Contact:

Re: OLEDrag&Drop

Post by TiKu »

Code: Select all

  Dim col As ListViewColumn
  
  For Each col In ExplorerListView1.Columns
    Debug.Print col.Caption, col.Index, col.Position
  Next col
  ' insert a column that becomes the 2nd column, but with index max+1
  ExplorerListView1.DontRedraw = True
  With ExplorerListView1.Columns
    Set col = .Add("Column " & CStr(.Count + 1))
    col.Position = 1
  End With
  ExplorerListView1.DontRedraw = False
  For Each col In ExplorerListView1.Columns
    Debug.Print col.Caption, col.Index, col.Position
  Next col
Dragging multiple columns is possible, but a bit complicated. I'll post code to do this later.
Crunching for Fab36_Folding-Division at Folding@Home. Join Fab36/Fab30! - Folding@Home and BOINC
Boycott DRM! Boycott HDCP!
Post Reply