Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

A Persistent Wait Cursor

0.00/5 (No votes)
26 Jan 2003 3  
A simple method of maintaining a wait cursor across messages

Introduction

To use the CWaitCursor class to show a wait cursor, an instance of the object is simply created. Destroying the object restores the normal cursor. However, the documentation states that although the lifetime of the object may span messages, the wait cursor is only guaranteed to remain on the screen for the duration of the currently processing message.

The purpose of this article is to describe a simple and neat method of allowing the wait cursor to persist across messages.

Background

The reason the wait cursor is not guaranteed to persist across messages is that as well as our messages using the wait cursor, the WM_SETCURSOR message may also be processed. The default processing of this message will cause the cursor to change. To prevent this from happening, WM_SETCURSOR needs to be handled, and if the wait cursor is to be shown, we need to call CCmdTarget::RestoreWaitCursor(), thus :

BOOL CMyWnd::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message)
{
    if (WaitCursorShown())
    {
        // We are showing the wait cursor

        RestoreWaitCursor();
        return TRUE;
    }

    // Let the base class deal with this one

    return CWnd::OnSetCursor(pWnd, nHitTest, message);
}

WaitCursorShown() is simple enough - all we need to do when we create the CWaitCursor is to set a variable to indicate this, and then of course, set the variable again to indicate the destruction of the CWaitCursor. However, this has the potential to get a little messy, particularly as we may well need to implement this in a number of windows (for example, CFrameWnd and CView derived classes). It is also rather error prone, as we have to make sure we update the variable accordingly wherever the CWaitCursor object is destroyed, because it goes out of scope.

CPersistentWaitCursor

CPersistentWaitCursor is a very simple class derived from CWaitCursor. Construction of a CPersistentWaitCursor object increments a reference count, to indicate that the wait cursor is to be shown. Similarly, destruction of the object decrements the reference count. Being derived from CWaitCursor, the constructor and destructor cause the wait cursor to be shown and hidden appropriately.

CPersistentWaitCursor offers only one more method than CWaitCursor, CPersistentWaitCursor::WaitCursorShown(). This returns a bool, to indicate whether or not the wait cursor should be shown, based on the value of the reference count.

Using CPersistentWaitCursor is very simple :

#include "PersistentWaitCursor.h"


void CMyWnd::DoSomeLengthyOperation()
{
    // Create and show the wait cursor

    CPersistentWaitCursor waitCursor;

    // Do some lengthy operation

    ...

    // waitCursor goes out of scope and cursor is restored

}

BOOL CMyWnd::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message)
{
    if (CPersistentWaitCursor::WaitCursorShown())
    {
        // We are showing the wait cursor

        RestoreWaitCursor();
        return TRUE;
    }

    // Let the base class deal with this one

    return CWnd::OnSetCursor(pWnd, nHitTest, message);
}

Reference counting is performed using a single instance of CPersistentWaitCursorMonitor, a simple class which maintains the count. Access to the count is protected using a critical section.

Conclusion

Because of the simplicity of the class, I have not included a demonstration of it's use.

The class has found use in the application I am currently developing. This application is very similar in style to Windows Explorer. Items in the tree represent rows in a database. Expanding these items performs two jobs - first, child items are loaded from the database and placed in the tree, and secondly data is taken from the child items, processed, and placed into a view. Both the loading of the database items (a function of the tree), and the processing (a function of the document / view) are lengthy operations, but appear to the user as single operation. CPersistentWaitCursor simplifies showing and managing the wait cursor whilst these operations take place.

History

  • 27th January 2003 - Updated to correct compiler error in source file (included non-existent file!)

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here