Animated Multithread Splash

A snapshot of the Shutter style splash

Splash is useful in many applications, especially in some slow-loading processes. There is a splash screen in Visual C++ ATL, but it has many useless functions and is somehow rigid. So, you can create a flexible splash.

To create the multithread splash, you can refer to the article "A Splash Screen with Alpha Blending," written by Leonardo Bernardini. In it, maybe there is something different from my splash class, but they are both based on the same technique.

How It Works

If you are not interested in it, you can skip this section and go to the next section, where you can learn how to use it.

As you can see, the splash screen is in fact a window without a title bar and board. So, you create a window to draw what you want.

You derive CUltraSplashWnd from the CWnd class and add a member function to create a real window: The first part creates an invisible window used as the parent so that the splash window won't show in the task bar. Here is the code:

BOOL CUltraSplashWnd::Create()
{
   //Create an invisible parent window
   LPCTSTR pszWndClass = AfxRegisterWndClass(0);
   m_wndOwner.CreateEx(0,
      AfxRegisterWndClass(0),
      _T(""),
      WS_POPUP,
      CW_USEDEFAULT,
      CW_USEDEFAULT,
      CW_USEDEFAULT,
      CW_USEDEFAULT,
      NULL,
      0);

   //Create splash window
   CreateEx(0,
      AfxRegisterWndClass(0,
      AfxGetApp()->LoadStandardCursor(IDC_ARROW)),
      "UltraSplashWnd",
      WS_POPUP | WS_VISIBLE,
      0,
      0,
      m_bm.bmWidth,      //Width of bitmap
      m_bm.bmHeight,     //Height of bitmap
      m_wndOwner.GetSafeHwnd(),
      NULL,
      NULL);

   ShowCursor(FALSE);    //Hide the cursor
   m_bClose = false;

   Show();
   return TRUE;
}

You use Show() to begin drawing.

void CUltraSplashWnd::Show()
{
   while (!m_bClose)
   {
      RedrawWindow();
   }
}

As you can see, this loop forces a redraw of the window, so that the animation can display. The animation implements in OnPaint(). You must create a memory DC to store the splash bitmap. After that, you check the animation style and jump to the corresponding drawing function.

void CUltraSplashWnd::OnPaint()
{
   CPaintDC dc(this);    // device context for painting
   m_pDC = &dc;
   //TODO: Add your message handler code here
   if(!m_MemDC.GetSafeHdc())
   {
      m_MemDC.CreateCompatibleDC(&dc);    //Create the memory DC to
                                          //store the bitmap
      m_MemDC.SelectObject(&m_bitmap);    //Select the bitmap to
                                          //the DC
   }

   bool bOver = false;

      switch (m_nStyle)
      {
      case USS_LEFT2RIGHT:     //left to right
         bOver = Left2Right(m_CtrlVal1);
         break;
      case USS_RIGHT2LEFT:     //right to left
         bOver = Right2Left(m_CtrlVal1);
         break;
      case USS_UP2DOWN:        //up to down
         bOver = Up2Down(m_CtrlVal1);
         break;
      case USS_DOWN2UP:        //down to up
         bOver = Down2Up(m_CtrlVal1);
         break;
      case USS_HORISHUTTER:    //horizontal shutter
         bOver = HoriShutter(m_CtrlVal1,m_CtrlVal2);
         break;
      case USS_VERTSHUTTER:    //vertical shutter
         bOver = VertShutter(m_CtrlVal1,m_CtrlVal2);
         break;
      case USS_RANDOMBOX:      //random box
         bOver = RandomBox(m_CtrlVal3);
         break;
      default:
         //Static drawing, copy picture to dc directly
         m_pDC->BitBlt(0, 0, m_bm.bmWidth, m_bm.bmHeight, &m_MemDC,
                       0, 0, SRCCOPY);
         break;
      }

      //set style to static after animated
      if (bOver) m_nStyle = USS_STATIC;

      // Do not call CWnd::OnPaint() for painting messages
}

For example: If you render the splash bitmap left to right, you use the function as follows:

Animated Multithread Splash

The render process is controlled by some member variables. The drawing functions use a reference to these control variables. Each calls the drawing function adds the control variable to 1, so it draws one column of the bitmap each time. When drawing to the right side, the function returns true and the style is set to static.

bool CUltraSplashWnd::Left2Right(int &i)
{
   if (i<m_bm.bmWidth)
   {
      m_pDC->BitBlt(i, 0, 1, m_bm.bmHeight, &m_MemDC, i, 0, SRCCOPY);
      i++;
      Sleep(1);
      return false;
   }
   else
      return true;
}

I just wrote seven drawing styles, it's easy to add your own drawing algorithm into the class. But, don't forget to initialize your control variables in SetStyle() and set the STYLE_COUNT to the styles' count.

How to Use

First of all, you can download the source files and add them into your app, which includes:

  • UltraSplash.cpp, UltraSplash.h
  • UltraSplashThread.cpp, UltraSplashThread.h
  • UltraSplashWnd.cpp, UltraSplashWnd.h

Now, you must include one header into your project; in general, you can paste the following code to your Application Class that derived from CWinApp:

//insert the header into your project
#include "UltraSplash.h"

Then, insert the following codes before the slow loading:

CUltraSplash splash;
splash.ShowSplash(IDB_BITMAP1, USS_RANDOM);

IDB_BITMAP1 is the ID of the bitmap resource. You can change IDB_BITMAP1 to any picture you like. Also, you can use a picture filename as the first parameter. The second parameter is an animation-style enumeration; you can find the enumeration at the top of the UltraSplashWnd.h file.

After the busy loading, you can hide the splash by using splash.HideSplash().

  • If your application is modal dialog-based, you would like to release the splash object by using splash.Destory(); before the call of DoModal().
  • If your application is another type, you would like to do nothing and the splash class can release itself in the destructor.

You must note that the call of HideSplash() just hides the splash window rather than destroys it. And, the call of marco Destory() not only releases the splash thread but also implicitly sets the focus to the main window. So, if you you don't want to call the Destroy(), add this line:

m_pMainWnd->SetForegroundWindow();

to set the focus to the main window, and the splash object will released in the destructor. After that, you can press F5 to see the result.

Note: To active the main window (the default is that the main window is set to the bottom of the z-order), I divide the hiding and destroying into two parts, HideSplash just hides the splash window; the Destroy method implicitly calls the DestroySplash(m_pMainhWnd). Before closing the splash screen, you set the Main window to the top. Maybe there is a better method to solve this problem.

In the end, as I said, I am a beginner and this my first article with CodeGuru. So, if you spot something that is incorrect in this code or you have any questions, please let me know by e-mailing me at: endether@hotmail.com.



About the Author

zheng chen

My name is ChenZheng. Now I am undergraduate student studying at Univ of Elec Sci & Tech of China. I am interested in PR, CG, VR and DB. If you are interested in some of them, maybe you can contact me freely with endether@yahoo.com.cn or endether_ca@yahoo.ca.

Downloads

Comments

  • There are no comments yet. Be the first to comment!

Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • Live Event Date: November 20, 2014 @ 2:00 p.m. ET / 11:00 a.m. PT Are you wanting to target two or more platforms such as iOS, Android, and/or Windows? You are not alone. 90% of enterprises today are targeting two or more platforms. Attend this eSeminar to discover how mobile app developers can rely on one IDE to create applications across platforms and approaches (web, native, and/or hybrid), saving time, money, and effort and introducing apps to market faster. You'll learn the trade-offs for gaining long …

  • Live Event Date: October 29, 2014 @ 11:00 a.m. ET / 8:00 a.m. PT Are you interested in building a cognitive application using the power of IBM Watson? Need a platform that provides speed and ease for rapidly deploying this application? Join Chris Madison, Watson Solution Architect, as he walks through the process of building a Watson powered application on IBM Bluemix. Chris will talk about the new Watson Services just released on IBM bluemix, but more importantly he will do a step by step cognitive …

Most Popular Programming Stories

More for Developers

Latest Developer Headlines

RSS Feeds