Threaded SplashScreen

C

Chris

I have a form that take a bit to load up because of talking to a database
and the amount of data process that has to take place before showing the
screen. I have it working but I feel that I horked it into working. I was
wondering if there was a better way to do this. Here are the two
interesting pieces of code. Thanks in Advance.


Sub Main
Dim Splash As New SplashScreen
Dim t As System.Threading.Thread
t = New System.Threading.Thread(AddressOf Splash.Process)
Splash.Show()
t.Start()
Dim CF As CommissionForm = New CommissionForm()
Splash.TimeToDie = True
t.Abort()
CF.ShowDialog()
End Sub

'This is Splash Screen code
Public Sub Process()
Do While Not Die
Application.DoEvents()
System.Threading.Thread.CurrentThread.Sleep(125)
Loop
Me.Hide()
Me.Close()
End Sub
 
N

Nak

Hi Chris,

When I use threads I allways put the routine in a try block so that it
can be aborted easily,

~~~~~~~

Public Sub Main
Dim Splash As New SplashScreen
Call Splash.Show()

Dim t As New Threading.Thread(AddressOf Splash.Process)
t.Priority = ThreadPriority.BelowNormal
t.IsBackground = True
Call t.Start()

Dim CF As New CommissionForm()
Call CF.ShowDialog()

Call t.Abort()
End Sub

~~~~~~~

Public Sub Process
Try

'This will loop continually while no exceptions are encountered and
the form is created
While Me.Created()

'This will redraw the form if need be
Call Me.Refresh()

'This will cause the thread to yield to the operator
Call Threading.Thread.Sleep()
End While
Catch
End Try

'Close the form now!
Call Me.Close()
End Sub

~~~~~~~

Usually if I track progress I make a form that is displayed topmost and
I refresh it every time my intensive loop completes, but I guess in your
case the accessing of the database wont allow you to do this? If that is
the case and there is no other way to get asynchronous reading from a
database you may want to try to put the code that reads from the database
into a separate thread to prevent it from locking your application up, make
your own BeginRead and AbortRead methods. Then once you have that
implemented you can track the progress in the usual way.

I hope this helps!

Nick.
 
C

Chris Dunaway

On Fri, 12 Nov 2004 13:11:58 -0600, Chris wrote:


Why not just show the splash screen and then close it when done? Why do
you need a thread?

Public Sub Main()
Dim Splash As New SplashScreen
Splash.Show()

Dim CF As CommissionForm = New CommissionForm()

Splash.Close
Application.Run(CF)
End Sub


--
Chris

dunawayc[AT]sbcglobal_lunchmeat_[DOT]net

To send me an E-mail, remove the "[", "]", underscores ,lunchmeat, and
replace certain words in my E-Mail address.
 
N

Nak

Hi Chris,

I think that if the applications thread gets blocked then the form will
not get refreshed, looking a bit on the pants side. Hence needing someway
of constantly keeping it repainted. At least that's what I presume he
means.

Nick.
 
L

Landley

Chris,

Firstly, try to avoid using DoEvents. There are many situations where this
could prove deadly to your applications.

I would suggest showing the splash screen. Use ThreadStart to start your
job with a waithandle or a class that derrives the waithandle. This way,
you do not need a "nasty" loop containing DoEvents.

Hope this helps.

Landers
 
C

Chris

Landley-

Your post has brought up a couple of questions in my mind.

First, I use the DoEvents in several places in my application to make sure
the screen is in a clean state, is this a bad practice in general. For
instance I have a point where I got grab a bunch of data after a combobox is
changed. The combobox freezes and doesn't redraw until the blocking call is
done, so I run a doevents and it works perfect.

Not shown in that code I gave is a call to another sub that shows a progress
bar so the user sees something happening while loading. There are many DB
calls to get the data needed to show the user and there is a decent delay in
processing it all. I think I need the DoEvents for this progress bar to
update nicely, do you disagree with using it in this instance still?

Chris
 
N

Nak

Sorry to jump in. But you might want to check this out,

http://geekswithblogs.net/jolson/articles/2173.aspx

This guy explains why you shouldn't use DoEvents in a game loop, and it's
pretty much for the same reason (in my opinion), especially if you are just
using it to enable the redrawing of a thread blocked form. *But*, that
doesn't mean you shouldn't use DoEvents full stop, you can "selectively"
yield to the operator by checking the message cue for any pending messages
*before* calling DoEvents, use the following to achieve this,

Private Const QS_HOTKEY As Integer = &H80
Private Const QS_KEY As Integer = &H1
Private Const QS_MOUSEBUTTON As Integer = &H4
Private Const QS_MOUSEMOVE As Integer = &H2
Private Const QS_PAINT As Integer = &H20
Private Const QS_POSTMESSAGE As Integer = &H8
Private Const QS_SENDMESSAGE As Integer = &H40
Private Const QS_TIMER As Integer = &H10
Private Const QS_ALLPOSTMESSAGE As Integer = &H100
Private Const QS_MOUSE As Integer = (QS_MOUSEMOVE Or QS_MOUSEBUTTON)
Private Const QS_INPUT As Integer = (QS_MOUSE Or QS_KEY)
Private Const QS_ALLEVENTS As Integer = (QS_INPUT Or QS_POSTMESSAGE Or
QS_TIMER Or QS_PAINT Or QS_HOTKEY)
Private Const QS_ALLINPUT As Integer = (QS_SENDMESSAGE Or QS_PAINT Or
QS_TIMER Or QS_POSTMESSAGE Or QS_MOUSEBUTTON Or QS_MOUSEMOVE Or QS_HOTKEY Or
QS_KEY)
Private Declare Function GetQueueStatus Lib "user32" (ByVal fuFlags As
Integer) As Integer

Public Sub selectiveYield()
If (CBool(GetQueueStatus(QS_ALLINPUT))) Then Call Application.DoEvents()
End Sub

I'm sure that Landers solution sounds more robust, but this can be
quickly implemented at key points during the application to prevent your
loop from slowing down unneccesarily by yielding with each loop. Hope this
helps.

Nick.
 

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