DropObject event handler odd behavior

I have the following code in the DropObject event handler of a desktop app main window:

Do If obj.FolderItemAvailable Then If obj.FolderItem.Type <> "" Then MediaForUse = InStr(AllAvailExt, obj.FolderItem.Type) /// determine whether the droped file extension is in my 'to use' list Select Case MediaForUse Case 117 To 254 /// it's a video ext. vFullPath = obj.FolderItem.NativePath vname_no_ext = Replace(obj.FolderItem.Name, obj.FolderItem.Type , "") vext = obj.FolderItem.Type vdir = obj.FolderItem.Parent.NativePath #If TargetMacOS Then vdir = vdir + "/" vname_with_ext = obj.FolderItem.Name ProcessMedia /// Go to process the media (may take a while) Case 0 To 116 /// it's an audio ext. Continue End Select End If End If Loop Until Not obj.NextItem

It works great on both Mac and Windows as long as I drag all media files in one go, but, and here is the tricky part, in case you have one video file in one folder and another in a different folder you can’t drag them together right, so you drag one and it starts to process (may take even an hour) and as long as the process is running you can’t add more files to the Cue.
So I tried to release the blockage by creating TheCue() As FolderItem

[code]Do
If obj.FolderItemAvailable Then
If obj.FolderItem.Type <> “” Then
MediaForUse = InStr(AllAvailExt, obj.FolderItem.Type) /// determine whether the droped file is in the ‘AllAvailExt’ Array
Select Case MediaForUse
Case 117 To 254 /// it’s a video ext.
TheCue.Append(obj.FolderItem)
Case 0 To 116 /// it’s an audio ext.
Continue
End Select
End If
End If
Loop Until Not obj.NextItem

If CueNotRunning Then
RenderCue
End If[/code]

RenderCue Method:

[code]For i As Integer = 0 To UBound(TheCue)
If TheCue(i).Exists Then
If TheCue(i).Type <> “” Then
MediaForUse = InStr(AllAvailExt, TheCue(i).Type) /// determine whether the droped file is in the ‘AllAvailExt’ Array
Select Case MediaForUse
Case 117 To 254 /// it’s a video ext.
vFullPath = TheCue(i).NativePath
vname_no_ext = Replace(TheCue(i).Name, TheCue(i).Type , “”)
vext = TheCue(i).Type
vdir = TheCue(i).Parent.NativePath
#If TargetMacOS Then vdir = vdir + “/”
vname_with_ext = TheCue(i).Name

    ProcessMedia /// Go to process the media (may take a while)
  Case 0 To 116                                  ///   it's an audio ext.
    Continue
  End Select
End If

End If
Next[/code]

Now it kinda lets me drag more objects but instead of adding them to the list it doubles the items that have been in the original drag and I can’t seem to add the new once.
All I want is to be able to drag/add more items to the process cue list while process is still running, any idea ?

Finder and the file are both locked during the DropObject event.

The only thing you should be doing in this event is creating a FolderItem reference to the dropped file. Processing the file should be threaded or delayed until the next event loop with a Timer.

Thanks Tim!

That is annoyingly true, didn’t bother to mention that really unwanted behavior but that is the least of you problems because it doesn’t lock other Finder windows and my users want to add files from other location so they only bothered by the fact that once the process starts and as I mentioned can last up to an hour per file, you can’t add more files to the list until it is all done.
If you have any idea how to add files to the Initial cue list once it started I’ll be thrilled to see a small example. I thought creating a FolderItem Array and using it in a separate method or timer would solve the problem but I can’t seem to get it to work properly for some reason.

Wrong:

Set the view to “by list”, click in the two folder black triangles to open both folders and you can select the two files located in two different folder.
I hope this is clear.

I do not know how this can help you, but I prefer to tells you.

  1. have the dropObject method place a reference in a queue, and start a threaded method if not already running
  2. that threaded method processes only one of the files… when it is done it checks if there is another, or it terminates, once it terminates the act of dropping a new file will restart it

That way the user can drop files at any time, and they are queued up without any timers or other such overhead

[quote=433759:@Dave S]1) have the dropObject method place a reference in a queue, and start a threaded method if not already running
2) that threaded method processes only one of the files… when it is done it checks if there is another, or it terminates, once it terminates the act of dropping a new file will restart it

That way the user can drop files at any time, and they are queued up without any timers or other such overhead[/quote]
Hi Dave, that is exactly what I’ve been trying to do but don’t know how to accomplish, as I was saying I created a FolderItem Array trying to buffer that queue and use it in a separate method but it seems my coding knowledge insufficient to achieve that goal :slight_smile:
If you can be kind enough to guide me with some code example I’ll be more than grateful.

since this is a window then the easiest is to put a thread object ON the widow by dragging one from the control palette to the window - it will be named Thread1 which is fine

then in your window you have a property, theCue() as folderitem and in the drop object event you just add to theCue

Do
  If obj.FolderItemAvailable Then
    If obj.FolderItem.Type <> "" Then
      MediaForUse = InStr(AllAvailExt, obj.FolderItem.Type)  ///  determine whether the droped file is in the 'AllAvailExt' Array 
      Select Case MediaForUse
      Case 117 To 254                                 ///    it's a video ext.
        TheCue.Append(obj.FolderItem)
      Case 0 To 116                                  ///   it's an audio ext.
        Continue
      End Select
    End If
  End If
Loop Until Not obj.NextItem


If Thread1.State <> Thread.Running Then 
  Thread1.Run
End If

Then add the RUN event handler to thread1 and put this code in it
This should be workable - but its all written in a forum post so its may only be close

While UBound(TheCue) >= 0
  If TheCue(0).Exists Then
    If TheCue(0).Type <> "" Then
      MediaForUse = InStr(AllAvailExt, TheCue(0).Type)  ///  determine whether the droped file is in the 'AllAvailExt' Array 
      Select Case MediaForUse
      Case 117 To 254                                 ///    it's a video ext.
        vFullPath = TheCue(0).NativePath
        vname_no_ext = Replace(TheCue(0).Name, TheCue(0).Type , "")
        vext = TheCue(0).Type
        vdir = TheCue(0).Parent.NativePath
        #If TargetMacOS Then vdir = vdir + "/"
        vname_with_ext = TheCue(0).Name
        
        ProcessMedia /// Go to process the media (may take a while)

      Case 0 To 116                                  ///   it's an audio ext.
        Continue
      End Select
    End If
  End If

  theCue.remove 0
wend

by putting the processing of each media item into the threads run event the UI should remain responsive

Wow @Norman Palardy that is amazing, thank you oh so much for your time. I will go and try to implant that right now !

I just took your code and split it into “the piece that does the processing” and made that a thread
and the rest of the drag handling is mostly the same

Yes I see that, I almost believed that the missing link had been found, but after I made the change I get this exception:

Maybe I should have mentioned I have quite extensive GUI textual Communications on the main window plus progress bar update all the way through plus Shell.Execute (mode 2) all happening in the [quote]ProcessMedia[/quote] method that I call now from within thread1 and It seems to be forbidden :frowning:

well the thread cannot directly manipulate the UI
Period
But what you can do in the thread is have properties for progress etc and then as part of the thread have it run a timer and that timers action can
or if you put the thread directly on the form as I suggested have the thread set properties on the form and then a timer takes those properties and updates the UI

[quote=433776:@Norman Palardy]well the thread cannot directly manipulate the UI
Period
But what you can do in the thread is have properties for progress etc and then as part of the thread have it run a timer and that timers action can
or if you put the thread directly on the form as I suggested have the thread set properties on the form and then a timer takes those properties and updates the UI[/quote]
Haha should be interesting @Norman Palardy :slight_smile:
So I Can set in the thread:

[code]ProcessIsRunning = True
ProcessHandleTimer.Mode = 2
While ProcessIsRunning

Wend[/code]
And in the Timer call the ProcessMedia method and when it’s done stop the timer and set ProcessIsRunning to False that will break the loop in the thread and let it continue to the next item ?

dont call processmedia in the timer
call it in the threads code otherwise the timer will end up blocking stuff

thats why you want processmediacalled by the threads run event
it makes that code & everything it calls threaded which means it wont block the UI

the timer is for taking a “progress measurement” from the thread and putting it in the UI

Oh I see, cool @Norman Palardy
Although this is getting a bit complicated because I have tons of UI updates within the process like progress bar status update, progress percentage visual display on the main window UI etc.
I’ll do my best to crack this Catch 22 conundrum, should be fun :slight_smile:

yeah this is the “simplest” way to attack this

basically when you want the ui to remain responsive you need to shove the processing into a thread as that can/will yield time back to the main thread of the application which handles UI updates etc
and then the trick is to figure out how to communicate the progress back to the UI with something NOT in the thread itself

all modern OS UI Kits basically require this - they didnt all used to

Okay then, I’ll roll my sleeves and get to work :wink:
Thanks for everything folks!