Question Problem With Threading on MouseEnter Event.

dHeather

Active member
Joined
Jun 18, 2012
Messages
27
Programming Experience
Beginner
Hello,


Can somebody tell me where I'm going wrong please?

I have a routine (below) that when a user hovers over a button a thumb is created in a picture box of the target file. The problem I have is that a lot of the target files are large and creating the thumb can take a while (up to a second). What I am trying to do is to add threading so I can interupt the MouseEnter event if the use clicks. I can't get it working though. Can anyone tell me where I'm going wrong please?

Thank you very much

My code is Below:

[XCODE]
Imports System.IO
Imports System.Drawing
Imports System.Threading '<----------

Public
Class Form1
Dim FileString, FolderString AsString
Dim myFiles AsNew List(Of IO.FileInfo)
Dim myButtons AsNew List(Of Button)
Dim t AsNew Thread(AddressOf Image_Buttons_MouseEnter) '<----------

Private
Sub Image_Button_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button6.Click, Button7.Click, Button8.Click, Button9.Click, Button10.Click, Button11.Click, Button12.Click, Button13.Click, Button14.Click, Button15.Click, Button16.Click, Button17.Click, Button18.Click, Button19.Click, Button20.Click, Button21.Click, Button22.Click, Button23.Click, Button24.Click, Button25.Click, Button26.Click, Button27.Click, Button28.Click, Button29.Click, Button30.Click, Button31.Click
t.Abort() '<---------
Dim CurrentBtn As Button = sender
Dim FileName AsString = myFiles(CurrentBtn.Text - 1).ToString
Try
Process.Start("D:\" & FolderString & myFiles(CurrentBtn.Text - 1).ToString)
Catch ex As Exception
EndTry
EndSub

Private
Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) HandlesMyBase.Load
For i AsInteger = 6 To 31
myButtons.Add(
Me.Controls("Button" & i))
Next i
Me.Label23.Parent = Me.Label22
Me.Label23.BackColor = Color.Transparent
Me.PictureBox1.Visible = True
Me.PictureBox1.Image = My.Resources.New_logo_4__small_
FolderString =
"acouStac Info\acouStac Photos\"
EndSub

PrivateSub Image_Buttons_MouseEnter(ByVal sender AsObject, ByVal e As System.EventArgs) Handles Button6.MouseEnter, Button7.MouseEnter, Button8.MouseEnter, Button9.MouseEnter, Button10.MouseEnter, Button11.MouseEnter, Button12.MouseEnter, Button13.MouseEnter, Button14.MouseEnter, Button15.MouseEnter, Button16.MouseEnter, Button17.MouseEnter, Button18.MouseEnter, Button19.MouseEnter, Button20.MouseEnter, Button21.MouseEnter, Button22.MouseEnter, Button23.MouseEnter, Button24.MouseEnter, Button25.MouseEnter, Button26.MouseEnter, Button27.MouseEnter, Button28.MouseEnter, Button29.MouseEnter, Button30.MouseEnter, Button31.MouseEnter
t.Start() '<----------
Dim CurrentBtn As Button = sender
Dim FileName AsString = myFiles(CurrentBtn.Text - 1).ToString
Dim TempImg As Bitmap = System.Drawing.Image.FromFile("D:\" & FolderString & FileName)
Dim ImgWidth AsSingle = TempImg.Width
Dim ImgHeight AsSingle = TempImg.Height
Dim newWidth AsInteger
Dim newHeight AsInteger
If TempImg.Width > TempImg.Height Then
newWidth = 300
newHeight = (newWidth / TempImg.Width) * TempImg.Height
Else
newHeight = 300
newWidth = (newHeight / TempImg.Height) * TempImg.Width
EndIf
Dim resized As Bitmap = New Bitmap(newWidth, newHeight)
Dim g As Graphics = Graphics.FromImage(resized)
g.DrawImage(TempImg,
New Rectangle(0, 0, resized.Width, resized.Height), 0, 0, TempImg.Width, TempImg.Height, GraphicsUnit.Pixel)
Me.PictureBox1.Image = resized
g.Dispose()
EndSub

Private
Sub Image_Buttons_MouseLeave(ByVal sender AsObject, ByVal e As System.EventArgs) Handles Button6.MouseLeave, Button7.MouseLeave, Button8.MouseLeave, Button9.MouseLeave, Button10.MouseLeave, Button11.MouseLeave, Button12.MouseLeave, Button13.MouseLeave, Button14.MouseLeave, Button15.MouseLeave, Button16.MouseLeave, Button17.MouseLeave, Button18.MouseLeave, Button19.MouseLeave, Button20.MouseLeave, Button21.MouseLeave, Button22.MouseLeave, Button23.MouseLeave, Button24.MouseLeave, Button25.MouseLeave, Button26.MouseLeave, Button27.MouseLeave, Button28.MouseLeave, Button29.MouseLeave, Button30.MouseLeave, Button31.MouseLeave
t.Abort() '<---------
Me.PictureBox1.Image = My.Resources.New_logo_4__small_
EndSub
PrivateSub ListView1_MouseDoubleClick(ByVal sender AsObject, ByVal e As System.Windows.Forms.MouseEventArgs) Handles ListView1.MouseDoubleClick
Try
Process.Start("D:\" & FolderString & Me.ListView1.SelectedItems(0).Text)
Me.Button5.Focus()
Catch ex As Exception
EndTry
EndSub

End
Class
[/XCODE]
 
Last edited:
You do realise that just about everything you want here is pretty much automatic if you use an ImageList control?
 
Hello,

Thanks for the quick response.

I started with an Image List but the resolution of the created preview (300x300) was very poor even on a 32 Bit Colour Depth so I swapped over to a picture box which displays perfectly.

If I can sort out how to interupt the MouseEnter event it should work fine, hence my query.
 
A quick update,

I thought that it might be the fact that I was trying to handle a thread during an event so I have moved the creation of the thumb into its' own sub, but still no luck.

I'm obviously missing something fundimental, but I just can't see what.

Any ideas anyone?

Thanks
 
Threads are simply not designed for this kind of task. They are designed to take infinitely repeating tasks out of the main program flow. They should be started once, usually in the form load, paused when necessary and aborted only when the task is no longer required. The subroutines they refer to should essentially be self contained. You can't stop the thread, feed it new values, and then start it again, at least not without a complete re-initialisation. You certainly can't tie it to an event!

Threading really can't help! What you really need to do is separate the creation of the thumbnail and the display so that when the mouse events occur the thumbnail (if 300 x 300 can really be described as a thumbnail) is already waiting and appears more or less instantaneously. In other words, if the existing ImageList control isn't of good enough quality for you, you really need to create your own version of it! At the very least you need to strip down the thumbnail creation routine (there appear to be at least two variables added that never get used!) and find a way to avoid the file read.
 
Thanks for that. It's been driving me nuts. I'll be pleased not to have to read another site about threading. I was tying myself up in knots.

If I create a set of 300 x 300 images and add them to Resources, then just update the PictureBox on the MouseEnter event is this a sensible solution? There are about 60 pictures. Or is this bad practice?

(Thanks also for pointing out the redundant variables. I hadn't noticed them, they must have been hanging around from old code.)
 
If this is a static set of images that the app provides you should definitely create the thumbnails at design time also.

As for a dynamic set of images and thumbnails, you don't need to create the same thumbnail each time you MouseEnter a button, do you? Once should suffice. To further speed things up you can start to create the thumbnails on a secondary thread from the form Load event. Store all the thumbnails in a Dictionary, for button MouseEnter you can check in dictionary if thumbnail is available, and if it not choose to either show a 'loading' image/message or spend that 'second' to create that thumbnail in UI thread.
 
Thanks for the great advice. My images are static so I will add them to Resources.

I will have a go at the dictionary idea too, not for the final program, just so I can get my head around threading.

Thanks again for all you help.
 
Hmm. Bad practice is as bad practice does for me. If it works with no obvious potential exceptions and you understand why and how it works then that's good enough for personal projects! However, if you're going to use mouse events as triggers just make sure that the target is big enough and avoid butting everything up together so that there is a clear distinction between in and out. Remember that the code in the event will be executed in full so you need to take some account of what happens if a user crosses a lot of targets in a short time. If you're sticking to a button for every picture with a single event covering them all you might want to think about using a different and more definite trigger.
 
Back
Top