Threading confusion!

G

Guest

Hello All!

So I'm trying to figure out threading. I got the basic idea of how to start
new threads, but getting a little lost with the form thing. I understand the
that form runs a single thread, and can't start a new thread from an object
within a form.

So, I have 8 pictureboxes on a form. The pictureboxes have, well, picture
images in them. So when the form loads, they load up one at a time. So I'm
thinking, start a thread for each OnPaint event for each box. But when I try
to start to set it up as a thread I get a Sub Delegate message tip.

I have read alot of articles, but not sure still of what to do. I tried to
call up the OnPaint event in a class, but that doesn't work. As far as I
know I might be going about this all wrong. I think if I start each OnPaint
event for the picture box on a thread, they should all load up at the samr
time. Maybe I'm wrong.

So if anybody has any ideas, or good article they have know of.
I would appreciate it.

TIA!

Rudy
 
M

Markus

So, I have 8 pictureboxes on a form. The pictureboxes have, well,
picture images in them. So when the form loads, they load up one at
a time. So I'm thinking, start a thread for each OnPaint event for
each box. But when I try to start to set it up as a thread I get a
Sub Delegate message tip.

Don't put the OnPaint event in a new thread - this does not make sense
(at least not in 99% of the cases). Because painting is normally done
really fast. What you might need in a new thread is the loading of the
images or some long running calculations.

So what you could do is (I might not get the point what exactly you are
on, but maybe it gives you some ideas):

1) Add the picture boxes in the InitializeComponent of your
Form/UserControl.

2) The PictureBoxes are shown immediately, but without an image, because
loading the image might take longer.

3) In the Load-event of the Form create a new thread to load the images.

4) For each image, that has successfully loaded, set it to the picture
box. Or if you want all of them appear at the same time, do it at
the end of loading all of them.

hope I got you right

Markus
 
M

Markus

Because painting is normally done really fast.

Let me make a short follow-up on this:

It is not quite true, that painting is fast, but painting can be made
fast/flicker-free using other methods than different threads. Mainly you
might be interested in using DoubleBuffering or a temporary image, where
you paint your graphics and only change the image to be displayed... and
this operation is very fast.

hope this clarifies additionally.

Markus
 
G

Guest

Hello Markus!

Thank you for the reply. I like your suggestions, but let me clarify a
little more. I didn't metion that my form also has an image and the size of
the form is 856, 680. So after reading you reply, I did a quick little test.
I took the image out of the main form, and the picture boxes loade very
fast. I put the image back in the form, and I have a little lag. I put a
sleep on the thread on the Paint event for the main form, for 1 sec, the main
form image loads up, but there where the picture boxes are, and even the
buttons don't fill in right way. they fill in 1 sec apart. If I set the
thread sleep to 5 sec, they fill in 5 sec apart.

So I'm assuming that it is all one thread on that form. So I figure if I can
load the main image first, this may speed things up.

I like your idea below, but how would I go about doing that? Loading the
image form the main form would be a non-safe thread, right. Because the
object is part of the form.


3) In the Load-event of the Form create a new thread to load the images.

Thanks!

Rudy
 
M

Markus

So I'm assuming that it is all one thread on that form. So I figure
if I can load the main image first, this may speed things up.

Yes. A form is single threaded by default. If you want to do something
different, you need to create a new thread and do this in another thread.

I like your idea below, but how would I go about doing that? Loading
the image form the main form would be a non-safe thread, right.
Because the object is part of the form.

Which object is part of the form? The image? Or the Thread object? Maybe
I didn't get you right, but this does not matter...

However, you could do something like this:

1) prerequisites (member vars)
------------------------------
// create a member var for the images, maybe a list:
private IList<images> _myImages;


2) create the thread and handle the thread events
the easiest might be to use the BackgroundWorker instead
of an own thread, because then you don't have to be concerned
about accessing the Form-Thread from your thread to modify
controls.
-----------------------------------------------------------
// somewhere in the load event (or the constructor, but I might
// prefer the load event of the form):
BackgroundWorker worker = new BackgroundWorker();
worker.DoWork += delegate(object sender, DoWorkEventArgs e)
{
_myImages = new List<images>();
for (int i=0; i<8; i++)
{
Image img = LoadMyImageFromSomewhere();
_myImages.Add(img);
}
}

worker.RunWorkerCompleted += delegate(object sender,
RunWorkerCompletedEventArgs e)
{
foreach (Image img in _myImages)
{
PictureBox pb = GetPictureBox();
pb.Image = img;
}
};

worker.RunWorkerAsync();



However, you might want to decide to use methods instead of the
inline-delegate statements - but I hope you got the point.

Only remember that you do NOT access (or set) the PictureBox.Image
property in the DoWork-event, as the DoWork event is NOT executed in the
same thread of the form and would throw an exception. But the
RunWorkerCompleted event provides exactly this feature.

I did something similar a while ago and set the image to the picture box
in the DoWork event by returning to the UI event... then you have a
behavior like in Windows Explorer when you load the thumbnail-view - as
soon as something is loaded it is displayed.


If still everything is unclear, feel free to email me (just remove the
REMOVE-THIS in my email address...

Markus
 
G

Guest

Hi Markus!

Thank you for your great suggestions! But, none of them really worked. But
I did discover something interesting. My picture boxes have a background
color set to Transpracy. When I set the background color to a color, they
load up just fine. Why do you think that is?

Thanks again for all your help!

Rudy
 
G

Guest

Hey Markus!

So I wrote a simple class like this
Public Class BtnLoginClass
Dim f As Loginfrm

Public Sub BtnLogTrs()
f.btnLogin.BackColor = BackColor.Transparent
End Sub

End Class

I'm getting a syntax of not declared on the second BackColor. Not sure why
that is?
The in my form_Load I'm calling the class
Dim Trans As New BtnLoginClass
Dim ChangeBack As New Thread(New ThreadStart(AddressOf
Trans.BtnLogTrs))
ChangeBack.Start()


My thought is to still try and load the boxes, and the change to
transperacy on another thread. Doe this make sence, or am I wasting my time?

Thanks!

Rudy
 
M

Markus

Rudy,
So I wrote a simple class like this
Public Class BtnLoginClass
Dim f As Loginfrm

Public Sub BtnLogTrs()
f.btnLogin.BackColor = BackColor.Transparent
End Sub

End Class

I'm getting a syntax of not declared on the second BackColor. Not sure why
that is?

It should be "Color.Transparent", not "BackColor.Transparent".


The in my form_Load I'm calling the class
Dim Trans As New BtnLoginClass
Dim ChangeBack As New Thread(New ThreadStart(AddressOf
Trans.BtnLogTrs))
ChangeBack.Start()

My thought is to still try and load the boxes, and the change to
transperacy on another thread. Doe this make sence, or am I wasting my time?

The change to trancparency on another thread does not make sense at all,
because of 2 things:
1) Changing a back color is done very fast - it's not worth creating a
second thread for this. Threads are only relevant if you have long
running things, such as loading an image from the network or a couple
of larger images from the local disk (or database lookups, or
whatever).
2) This will throw an exception, because when you want to manipulate a
user control (e.g. its BackColor), then you need to return to the
main thread.
So what I am saying here is, that you just create a thread with
returning to the main thread as the only thing to do.

Additionally, using the BackgroundWorker might be easier than using the
System.Threading namespace, as it offers the DoWork and RunCompleted
events, that is automatically returned to the main user thread...

hope this helps with clarification

Markus
 
G

Guest

Hello Markus!

Ok, that does make sense. And is the BackgroundWorker part of VS 2003. I
should have metioned I'm not using 2005 yet. If it is, I'll find it.
I'll let you kow how it goes!

Thanks!
Rudy
 
M

Markus

Ok, that does make sense. And is the BackgroundWorker part of VS
2003. I should have metioned I'm not using 2005 yet. If it is, I'll
find it. I'll let you kow how it goes!

I don't know about VS, as I never use it... However, I assume, that you
are still using .NET Framework 1.0 or 1.1. I checked the documentation,
and the BackgroundWorker is not there - so it seems to be a new feature
of the .NET Framework 2.0...

Well, doesn't matter, go ahead with creating a new
System.Threading.Thread - this should also work. You just need to go
back to the Forms thread, when changing anything on ANY user control or
form element. You do this by a call to BeginInvoke of the form or
affected control.

Markus
 
G

Guest

Hi Markus!

Well, I finally got it it to work! I appreciate you sticking with me on
this one. I feel I have a pretty good understanding of threading. Thanks
again for all your help!!!

Rudy
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top