Mouse Progress Control

Introduction

This article introduces a mouse progress control that follows the mouse. The solution is based on global Windows hooking and it uses a DLL that is dynamically imported to the application.

Background

I have created several applications and utils that process a lot of information. Usually, it is time consuming and the users have to wait. I used to create a popup window with a progress bar to indicate the wait time; sometimes the GUI itself contained the progress. After a search for a better solution, someone suggested that I set the mouse cursor with the hourglass. The hourglass is a good idea, but I wanted it to show a progress bar.

I tested two solutions for the "problem." The first solution was 100 mouse cursors that contained the mouse and a progress bar. That solution did work, but several users complained about their "fancy" cursor, so I changed to my dull cursor-look. The second solution was to hook the system and create an owner draw progress control that followed the mouse. That resulted in this article.

I'm just finishing a new version of SizeMe; the music mode part of the program takes a while because it reads each MP3-file ID-tag, indexes it, sorts it, and then groups it. That process takes time and the user had to have some feedback on that. Because SizeMe has a clean GUI, I thought this would be a great idea. That is the main reason I created this control in the first place, but, hey, I love to share.

Layout

I'm more of a programmer than a designer. But, I did create two out of three designs in this control. Here are the three flavors:

Design Sample Description
Smooth This style looks like the default progress control with the PBS_SMOOTH option turned on. It is plain looking and it is possible to add a "percent" text on top of it.
Mac This style is sooo good looking. The idea and design were originally by Paul M. Meidinger ("Macintosh-like Progress Control"). It uses degrades of the selected colors. Also, here is it possible to add a percent on top of it.
Round This little puppy is my "masterpiece." Inspired by the Mac-control and some progress bars I saw in games, I decided to create a round-looking progress bar. It is possible to customize on which angle it should start and end, plus the width of the progress fillings.

Using the Code

The Mouse progress class uses a DLL that sets a system-wide hook. That does not mean that you need to add the .lib-file to the project because the DLL is dynamically loaded. To implement the code into your existing project, you only need to add these files:

  • MousePrg.cpp
  • MousePrg.h
  • MousePrgVars.h
  • MousePrgHook.h

And copy the MousePrgHook.dll file to where the executable file is.

You should create the class on the heap and delete it when you're finished. (Remember, because it uses a hook, the DLL will load into each program that is active after execution, and it does not need to be active when not in use!) A typical usage of it could be like this:

//Class defs
CMousePrg *pMProgress;
//(...)

//When you start a time-consuming process (this is an MFC example;
//on Win32, you usually have the instance/hwnd handles)
pMProgress = new CMousePrg(AfxGetInstanceHandle(),
   this->GetSafeHwnd());
//(...)

//While you are moving along processing your stuff
pMProgress->SetPercent(nPercent);

//Delete the progress when you're finished.
if(bFinished==TRUE)
{
   delete pMProgress;
   pMProgress=NULL;
}
//(...)

The CMousePrg class inits the hook and start drawing the progress. It will show until you delete the object. It is meant to be that way, so you are "forced" to delete the class and the hook get detached. (Many hooks might slow things down, I guess).

Mouse Progress Control

Defaults

The defaults are listed in the MousePrgVars.h header file. Here is the list over the defaults and which choices available.

Option Default Value Description
#define CLASS_MOUSEPROGRESS "STATIC_MOUSE_CLASS_WINDOW" Name of the class used for drawing the progress control. Could be any name, but it has to be unique
#define WM_PROGRESS_POSITION PROGRESS_BOTTOM Placement of the progress control around the mouse cursor. Valid values: PROGRESS_TOP, PROGRESS_BOTTOM, PROGRESS_LEFT, PROGRESS_RIGHT.
#define WM_PROGRESS_HORISONTAL_HEIGHT 20 Horizontal height of the control
#define WM_PROGRESS_HORISONTAL_WIDTH 100 Horizontal width of the control
#define WM_PROGRESS_VERTICAL_HEIGHT WM_PROGRESS_HORISONTAL_WIDTH Vertical height of the control. Usually the opposite of the horizontal
#define WM_PROGRESS_VERTICAL_WIDTH WM_PROGRESS_HORISONTAL_HEIGHT Vertical width of the control. Usually the opposite of the horizontal
#define WM_PROGRESS_ROUND_SIZE 60 This is the width and height of round styled progress control
#define WM_PROGRESS_TYPE PROGRESS_MAC This is the style of the control. It has three choices: PROGRESS_SMOOTH, PROGRESS_MAC, and PROGRESS_ROUND (the round style ignores the WM_PROGRESS_POSITION)
#define WM_PROGRESS_COLOR RGB(255,0,0) Default color of the progress fills. It is valid for all three styles
#define WM_PROGRESS_COLOR_BACKGROUND RGB(200,200,200) Default background color of the progress. It is valid for all three styles (cannot be changed on the fly, for no reason
#define WM_PROGRESS_COLOR_SHADOW RGB(0,0,0) When the option WM_PROGRESS_TYPE is set to PROGRESS_MAC and it is shown on position TOP or BOTTOM, this color is drawn in front of the progress bar.
#define WM_PROGRESS_ROUND_WIDTH 12 The width of the bar based of the progress bar (should not be equal to or wider than WM_PROGRESS_ROUND_SIZE/2)
#define WM_PROGRESS_ROUND_ANGLE 130 This is the angle that we cut from. A value of 130 will show a circle from -130 degrees to 130 degrees.
#define WM_PROGRESS_TEXT PROGRESS_YES Shows a percent text on top of the smooth and Mac-styled controls
#define WM_PROGRESS_TEXT_FONT "Verdana" Font name of the percent text
#define WM_PROGRESS_TEXT_SIZE 12 Font size of the percent text
#define WM_PROGRESS_TEXT_COLOR RGB(255,255,255) Text color of the percent text
#define WM_PROGRESS_TEXT_ALIGN (DT_SINGLELINE | DT_VCENTER | DT_CENTER) Font output options when the text is drawn to the screen

Known Issues

I haven't found a good way to detect whether a HWND is a context menu or not. There have been several attempts to detect that, but no success. I wanted the progress bar to be hidden when a context menu was open. That way it wouldn't slide in the background when you select it. I've tried to catch the WM_INITMENU and WM_EXITMENU messages, but the WH_GETMESSAGE hook does not seem to catch those. Any suggestions on this problem would be great!

Another problem is when a message queue inits a modal dialog that locks the parent queue. In those cases, you have to run the Hide() function to hide the progress quickly.

Points of Interest

System-wide hooks are a cool feature, but they has some challenges along the way. I wanted the mouse progress control to work on many different instances at the same time. But, that does not work when the DLL file is named the same. It seems to me that Windows is so "smart" that a DLL file loaded twice with the same name does not get loaded a second time. I did some searching and found different solutions to the problem. Earlier on, I used the BASS Sound SDK. Ian (the programmer of BASS) handled different instances of the library by copying the file with a unique name, and then loading it. That worked for me too, and the system is hooked once per instance created by the class.

History

v1.0: First public release



About the Author

Lars Werner

Thnx for viewing my article...

Check out some of my projects:

http://lars.werner.no/sizeme/ - Ultimate tool for maximize your output on CD/DVDs!

http://lars.werner.no/unpacker/ - Auto extract of multiple archives (RAR/ZIP) with queue support and cleanup options!

http://lars.werner.no/vnc/ - Fullscreen captionbar modified VNC clones (RealVNC, UltraVNC and TightVNC)

Visit http://lars.werner.no/ for more info!

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

  • You probably have several goals for your patient portal of choice. Is "community" one of them? With a bevy of vendors offering portal solutions, it can be challenging for a hospital to know where to start. Fortunately, YourCareCommunity helps ease the decision-making process. Read this white paper to learn more. "3 Ways Clinicians can Leverage a Patient Portal to Craft a Healthcare Community" is a published document owned by www.medhost.com

  • It's time high-level executives and IT compliance officers recognize and acknowledge the danger of malicious insiders, an increased attack surface and the potential for breaches caused by employee error or negligence. See why there is extra emphasis on insider threats.

Most Popular Programming Stories

More for Developers

Latest Developer Headlines

RSS Feeds