Mega Code Archive

 
Categories / Delphi / System
 

How to flash the taskbar button of an application

Notifying the user that attention to your program is needed by flashing the taskbar button, the window, or both. -------------------------------------------------------------------------------- If the application you are building is targeted at Windows 98 or above, you can use the API call FlashWindowEx and pass it a FlashWInfo structure. If you are targeting Windows 95 your options are more limited, and you have to use a timer to achieve the desired result. FlashWindowEx A TFlashWInfo structure is needed to hold the information Windows needs to do its job when you make the API call. Luckily all the work has been done for you, and Delphi already knows about the structure. It is declared in Delphi like this: type TFlashWInfo = record cbSize : LongInt; hWnd : LongInt; dwFlags : LongInt; uCount : LongInt; dwTimeout : LongInt; end; All you need to do is to populate the record and call the API function. For this example I have placed both in the OnClick event of a button, but you can of course locate them wherever suits you: procedure TForm1.Button1Click(Sender: TObject); var FWinfo: TFlashWInfo; begin FWinfo.cbSize := 20; FWinfo.hwnd := Application.Handle; // Handle of Window to flash FWinfo.dwflags := FLASHW_ALL; FWinfo.ucount := 10; // number of times to flash FWinfo.dwtimeout := 0; // speed in ms, 0 default blink cursor rate FlashWindowEx(FWinfo); // make it flash! end; Note that the flag shown against the dwflags property determines what the call does with the flashing, and the following constants are defined: FLASHW_STOP = 0 // Stop flashing FLASHW_CAPTION = 1 // Flash the window caption FLASHW_TRAY = 2 // Flash the taskbar button FLASHW_ALL = 3 // Flash both the window caption and taskbar button FLASHW_TIMER = 4 // Flash continuously, until the FLASHW_STOP flag is set FLASHW_TIMERNOFG = 5 // Flash continuously until the window // comes to the foreground This should work fine with Windows 98 and above. If you want to work with Windows 95, however, you will need to take a different approach: FlashWindow Under Windows 95 (and Delphi versions 3 and below which do not include the appropriate API wrapper) a different approach is needed. With this operating system the FlashWindowEx API call does not exist, and you need to use FlashWindow instead. (The FlashWindow call will work under later operating systems as well.) The problem with FlashWindow is that it only works once, so to achieve the required flashing button it is necessary to use a system timer. This, of course, uses up valuable resources - but it does achieve the desired effect. For the purposes of this example you need to create a form and drop a Timer and a Button onto it. Then select the Timer and double click the OnTimer event to create the event handler. Then add the following code: procedure TForm1.Timer1Timer(Sender: TObject); begin FlashWindow(Application.Handle, True); end; Next, you need to start the flashing. To do this simply use the button OnClick event to set the Enabled property of the Timer to True. In this example I have used the button event to toggle the flashing on or off: procedure TForm1.Button1Click(Sender: TObject); begin Timer1.Enabled := not Timer1.Enabled; end; So there you have it. Two different ways to achieve the same thing. © Chris Bray /Vertical Software 2002 Update Within minutes of posting this example Simon Clayton got in touch to suggest a way of causing the flashing ONLY if the application is not the currently active one. Over to Simon: I've done it like this: procedure TForm1.Timer1Timer(Sender: TObject); begin if (GetForeGroundWindow()<>Form1.Handle) then begin FWinfo.cbSize := 20; FWinfo.hwnd := Application.Handle; FWinfo.dwflags := FLASHW_ALL; FWinfo.ucount := 5; FWinfo.dwtimeout := 0; Flashing := True; FlashWindowEx(FWinfo); end else if (Flashing) then begin FWinfo.cbSize := 20; FWinfo.hwnd := Application.Handle; FWinfo.dwflags := FLASHW_STOP; FWinfo.ucount := 0; FWinfo.dwtimeout := 0; FlashWindowEx(FWinfo); Flashing := false; end; end; I have also put some code in the Form's onPaint event to stop the flashing: procedure TForm1.FormPaint(Sender: TObject); begin if (Flashing) then begin FWinfo.cbSize := 20; FWinfo.hwnd := Application.Handle; FWinfo.dwflags := FLASHW_STOP; FWinfo.ucount := 0; FWinfo.dwtimeout := 0; FlashWindowEx(FWinfo); end; end; The only problem I have now to solve is that if I am using an app on my second monitor and the form is on top on my first monitor then the onPaint event doesn't seem to get called when I switch back to the application which means that the flashing carries on - something I've noticed is a problem in MS Instant Messenger sometimes anyway. Well done Simon - great tip!