Click here to Skip to main content
15,860,859 members
Articles / Desktop Programming / MFC
Article

Mouse progress control

Rate me:
Please Sign up or sign in to vote.
4.87/5 (37 votes)
29 Mar 2006CPOL6 min read 87.3K   2.6K   81   16
A progressbar control that follows the mouse cursor using a system wide hook

Sample Image - mouseprogress.gif

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 progressbar to indicate the wait time; sometimes the GUI itself contains the progress. After a search for a better solution someone suggested to set the mouse cursor with the hourglass. The hourglass is a good idea, but I wanted it to show a progressbar.

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

I'm just finishing off a new version of SizeMe and the music mode part of the program takes a while since 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. Since SizeMe has a clean GUI I thought this would be a great idea. That is the main reason why 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 2 out of 3 designs in this control. Here are the three floors:

  • Smooth

    Image 2

    This style looks like the default progress control with PBS_SMOOTH option on. It is plain looking and it is possible to add a percent text on top of it.

  • Mac

    Image 3

    This style is much more good looking. The idea and design is originally made by Paul M. Meidinger ("Macintosh-like Progress Control"). It uses degrades of the selected colors. In addition, here it is possible to add percent on top of it.

  • Round

    Image 4

    This little puppy is my "masterpiece". Inspired by the Mac-control & some progress bars I saw in games I decided to create a round-looking-progressbar. It is possible to customize at which angle it should start and end, plus the width of the progress fillings.

Using the code

The Mouse progress class uses a DLL which 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 since 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:

C++
//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).

Defaults

The defaults are listed in the MousePrgVars.h header file. Here is the list of the defaults and the choices that are available:

OptionDefault ValueDescription
#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_POSITIONPROGRESS_BOTTOMPlacement of the progress control around the mouse cursor. Values valid: PROGRESS_TOP, PROGRESS_BOTTOM, PROGRESS_LEFT, PROGRESS_RIGHT.
#define WM_PROGRESS_HORISONTAL_HEIGHT20Horizontal height of the control
#define WM_PROGRESS_HORISONTAL_WIDTH100Horizontal width of the control<ontal>
#define WM_PROGRESS_VERTICAL_HEIGHTWM_PROGRESS_HORISONTAL_WIDTHVertical height of the control. Usually the opposite to the horizontal
#define WM_PROGRESS_VERTICAL_WIDTHWM_PROGRESS_HORISONTAL_HEIGHTVertical width of the control. Usually the opposite to the horizontal
#define WM_PROGRESS_ROUND_SIZE60This is the width and height of round styled progress control
#define WM_PROGRESS_TYPEPROGRESS_MACThis 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_COLORRGB(255,0,0)Default color of the progress fills. It is valid for all three styles
#define WM_PROGRESS_COLOR_BACKGROUNDRGB(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_SHADOWRGB(0,0,0)When the option WM_PROGRESS_TYPE is set to PROGRESS_MAC and it is shown on position TOP or BOTTOM then this color is drawn in front of the progress.
#define WM_PROGRESS_ROUND_WIDTH12The width of the bar based of the progress bar (should not be equal or wider than WM_PROGRESS_ROUND_SIZE/2)
#define WM_PROGRESS_ROUND_ANGLE130This is the angle that we cut from. A value of 130 will show a circle from -130 degree to 130 degree.
#define WM_PROGRESS_TEXTPROGRESS_YESShow 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_SIZE12Font size of the percent text
#define WM_PROGRESS_TEXT_COLORRGB(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 if a HWND is a context menu or not. There have been several attempts to detect that, but with no success. I wanted the progressbar to be hidden while a context menu was opened. That way it wouldn't slide in the background while you select. I've tried to catch the WM_INITMENU and WM_EXITMENU messages but the WH_GETMESSAGE hook does not seem to catch those. Any suggestion 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 quickly hide the progress.

Points of Interest

System wide hooks are a cool feature, but it 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 did use 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 loaded it. That worked for me too, and the system is hooked once per instance created by the class.

History

  • v1.0 - First public release

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Engineer A/S Norske Shell (Dutch Shell)
Norway Norway
----------------------------------
Visit http://lars.werner.no/ for my blog!
----------------------------------
Retired programmer, Norway never had the jobs I wanted Smile | :)

Comments and Discussions

 
Questionc# dll Pin
amin.naghdbishi28-Sep-13 5:18
amin.naghdbishi28-Sep-13 5:18 
AnswerRe: c# dll Pin
Lars [Large] Werner2-Oct-13 8:07
professionalLars [Large] Werner2-Oct-13 8:07 
QuestionCan not GetProcessAddr in Unicode Project Pin
AndrewSoyal21-Jul-09 0:36
AndrewSoyal21-Jul-09 0:36 
GeneralNice one Pin
Nibu babu thomas11-Jun-06 17:23
Nibu babu thomas11-Jun-06 17:23 
Generalsmall program Pin
Elias Bachaalany3-Apr-06 21:19
Elias Bachaalany3-Apr-06 21:19 
GeneralRe: small program Pin
Lars [Large] Werner5-Apr-06 7:51
professionalLars [Large] Werner5-Apr-06 7:51 
GeneralAnother "Me likes" message Pin
Iain Clarke, Warrior Programmer31-Mar-06 4:39
Iain Clarke, Warrior Programmer31-Mar-06 4:39 
GeneralRe: Another "Me likes" message [modified] Pin
Lars [Large] Werner31-Mar-06 7:34
professionalLars [Large] Werner31-Mar-06 7:34 
GeneralGood Idea Pin
Steve Thresher30-Mar-06 0:49
Steve Thresher30-Mar-06 0:49 
GeneralRe: Good Idea Pin
Lars [Large] Werner30-Mar-06 2:30
professionalLars [Large] Werner30-Mar-06 2:30 
GeneralRe: Good Idea Pin
Steve Thresher30-Mar-06 3:14
Steve Thresher30-Mar-06 3:14 
GeneralRe: Good Idea Pin
Lars [Large] Werner30-Mar-06 6:24
professionalLars [Large] Werner30-Mar-06 6:24 
GeneralNeat, useful and cool. Pin
Neville Franks29-Mar-06 23:37
Neville Franks29-Mar-06 23:37 
GeneralRe: Neat, useful and cool. Pin
Lars [Large] Werner30-Mar-06 2:33
professionalLars [Large] Werner30-Mar-06 2:33 
GeneralNice Pin
AnasHashki29-Mar-06 22:18
AnasHashki29-Mar-06 22:18 
GeneralRe: Nice Pin
conrad Braam3-Apr-06 23:02
conrad Braam3-Apr-06 23:02 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.