I <3 Steve McConnell*
Coding Horror
programming and human factors
by Jeff Atwood

January 07, 2005

Perceived Performance and Form.Paint

As a followup to my caution about exceptions in Form.Paint(), I wanted to illustrate why this technique is so effective. Let's say you had a form with this code:

    Private IsFirstPaint As Boolean = True

    Private Sub DoWork()
        Cursor = Cursors.WaitCursor
        StatusBar1.Text = "Loading..."
        System.Threading.Thread.Sleep(2000)
        For i As Integer = 0 To 99
            ComboBox1.Items.Add("ComboBoxItem " & i)
            System.Threading.Thread.Sleep(5)
        Next
        ComboBox1.SelectedIndex = 4
        System.Threading.Thread.Sleep(2000)
        For i As Integer = 0 To 99
            ListBox1.Items.Add("ListBoxItem " & i)
            System.Threading.Thread.Sleep(5)
        Next
        ListBox1.SelectedIndex = 4
        StatusBar1.Text = "Ready."
        Cursor = Cursors.Default
    End Sub

    Private Sub Form1_Load(ByVal sender As System.Object, _
      ByVal e As System.EventArgs) Handles MyBase.Load
        DoWork()
    End Sub

    Private Sub Form1_Paint(ByVal sender As Object, _
      ByVal e As System.Windows.Forms.PaintEventArgs) _
      Handles MyBase.Paint
        If IsFirstPaint Then
            IsFirstPaint = False
            Application.DoEvents()
            DoWork()
        End If
    End Sub

So either we're doing 5 seconds of work in Paint, or we're doing 5 seconds of work in form Load. Here's what it looks like when the work is done in Form.Load:

movie of Form Load doing work

And here's what it looks like when the work is done in Form.Paint:

movie of Form Paint doing work

The amount of time is the same in both cases, but guess which one users will tell you is "faster"? Perceived performance is more important than actual performance.

Sure, you can do a lot better job with threading, but I guarantee that'll take a lot more work than three lines of code! That's why I love the IsFirstPaint and DoEvents combo: maximum benefit for minimum effort.

Posted by Jeff Atwood    View blog reactions

 

« Moving the Block There Ain't No Such Thing as Plain Text »

 

Comments

Those little gif movies are so awesome/effective - what did you use to make them?

David Grant on January 7, 2005 07:35 PM

I've used Gif-gif-gif in the past, which is positively ancient but still works fine and produces very tiny GIFs:

http://www.peda.com/ggg/

now I use Camtasia studio, which is a great product and far more flexible. Also more expensive, but it can render to flash or AVI as well, and with some neat options like sound/visual effects for keypresses and mouseclicks:

http://www.techsmith.com/products/studio/default.asp

Jeff Atwood on January 7, 2005 10:35 PM

Couldn't you achieve the same effect by calling either Application.DoEvents() or this.Refresh() in the Form_Load event?

- Joshua

Joshua Bair on January 8, 2005 12:15 PM

Just answered my own question. DoEvents and Refresh do nothing until the form is visible. So how about this.Show() in Form_Load? I tested it, and it appears to do the same thing as the Form_Paint solution above, and it's only one line of code.

The only problem that I see is that there may be some way to load a form without showing it, although I don't know of any. This "trick" would affect that. I would say that the this.Show() solution would work for most, if not all situations.

- Joshua

Joshua Bair on January 8, 2005 12:23 PM

Interesting. That does appear to work, and the debugger picks up the correct line of code in Load() exceptions, too.

Jeff Atwood on January 8, 2005 07:36 PM

So, the moral of the story is:

Always call this.Show() in the Form_Load event?

I'll have to go back and add this to my last project. There are several instances where a dialog will appear after a few seconds of waiting, causing the user to usually try to open it 2 or 3 times.

- Joshua

Joshua Bair on January 8, 2005 08:47 PM

I wouldn't say "always" because we don't know if there are any side-effects yet. But yes, if you have a form that does a few seconds (or more) worth of work, I'd say try one of the Paint() or Load() DoEvents techniques first as a quick easy solution. If you need *real* threaded background processing, then look into the BackgroundWorker solution.

Anyway definitely try it and post your feedback here. I'd try it in our project but that's in offshore mode now. I'm disinclined to make a bunch of sweeping changes in the way we display forms..

Jeff Atwood on January 8, 2005 10:02 PM







(hear it spoken)


(no HTML)




Content (c) 2008 Jeff Atwood. Logo image used with permission of the author. (c) 1993 Steven C. McConnell. All Rights Reserved.