Task-bar Icons in Delphi

Under Windows 7, the familiar task bar underwent something of an overhaul. Tasks which once represented the title bar of an application were replaced with icons, each of which supports application previews, progress indicators, and overlay icons to provide additional information about the state of the application. In this post, I’d like to show you how you can interact with these icons to provide the same feedback for your Delphi applications.

This is a feature which has been in Delphi for several versions, but until today, I’d more or less ignored it. You see, despite the fact that I know, first hand, that customers demand modern UX features from their applications, I still find myself slipping back into considering UX an after-thought. I see this as one of my failings, but I don’t think it’s uncommon among software engineers.

In recent years, Embarcadero has put a lot of effort into making it possible to modernize your Delphi applications, and though a small feature, this one adds just that little extra polish.

Features of the Task-Bar Icon.

Lets take a look at the features of the task bar icon, and see which we can work with and how we do that. Note that I’m using Windows 10, and therefore the screenshots will take the Windows 10 form with the default theme colors, however, the features are the same as those in Windows 7.

  • It’s now an icon, not a title bar.
    We don’t need to do anything here, windows has created the task bar icon for us, it’s a built in part of the Windows UI, and actually started to appear in Windows XP but wasn’t fully implemented until Windows 7. Here’s a side by side of the newer icon based task bar and the older XP task bar…
     
  • Task Previews
    Again, we don’t need to do anything to get an application preview, the Windows UI will take care of this one for us. Hover your mouse over any running application and you should see a preview of that application…
  • Progress Indicators.
    If your application is running some long running process, the task bar icon can be used to provide a progress indication. This indicator has several available colors and animations representing different application states. We’ll take a look at how to provide these progress indicators using the TTaskBar component.
      
  • Icon Overlays.
    Each task bar icon may have a second icon overlaid onto it to provide additional information. For example, a media application when playing some media file, can overlay a ‘play’ icon, and similarly a pause icon when paused. We’ll look at how to add overlay icons using the TTaskBar component.
  • Jump Lists.
    When you right click on an icon in the task bar, you’re presented with a menu which typically has options to pin the application to the task bar as a short-cut, and to launch the application. This menu may also include options to launch the application with some context, such as opening a recently opened document, or opening the application to a particular feature state. We’ll take a look at how to add these items using a TJumpList component.
  • The application icon.
    Finally, of course, you can alter the icon it’s-self for your application. This is not something I plan to cover in this post, as I’ve covered this in a previous post, which you can see here.

So, now that we’ve seen the available features, lets go ahead and take a look at those we can interact with.

The progress indicator.

Start a new vcl application and drop a TTaskBar component, a TButton component, and a TTimer component onto the main form.
Set the TTimer.Enabled property to false, and set it’s Interval property to 100.
Add this code into the button OnClick handler…

procedure TForm1.Button1Click(Sender: TObject);
begin
  TaskBar1.ProgressMaxValue := 100;
  TaskBar1.ProgressState := TTaskBarProgressState.Normal;
  TaskBar1.ProgressValue := 0;
  Timer1.Enabled := True;
end;

And add this code to the Timer OnTimer event handler.

procedure TForm1.Timer1Timer(Sender: TObject);
begin
  TaskBar1.ProgressValue := Succ(TaskBar1.ProgressValue);
  if TaskBar1.ProgressValue=100 then begin
    Timer1.Enabled := False;
  end;
end;

Now run your application, click the button, and notice the green progress indication on your task bar icon. Pretty huh?
This is all quite straight forwards if you’re familiar with the way that VCL progress bars work, because it works in the same way. You set a maximum value for the progress indicator, and then increment the indicator value over time.

The important line to notice however is this one..

TaskBar1.ProgressState := TTaskBarProgressState.Normal;

This line sets the progress bar state from it’s default ‘none’ to ‘normal’. There are five states to choose from, each presenting a different color or different animation on the task bar icon. Feel free to experiment with the available options:

  • None
  • Indeterminate
  • Normal
  • Error
  • Paused

The overlay icon.

As I mentioned earlier, you can also add an icon to overlay onto your task bar icon. This is done by assigning an icon to the TTaskBar.OverlayIcon property. Rather than load an icon at run-time, lets use the designer to load one for us.

Drop a TImage component on your form and load an icon file into it’s picture property. You should select a windows .ico format file.
If you don’t have an appropriate icon of your own, you can download mine from this zip file
Now set the visible property of the image control to False, so that it doesn’t show up when we run the application.
Adjust the button OnClick handler, and Timer OnTimer handler as follows..

procedure TForm1.Button1Click(Sender: TObject);
begin
  TaskBar1.ProgressMaxValue := 100;
  TaskBar1.ProgressState := TTaskBarProgressState.Normal;
  TaskBar1.ProgressValue := 0;
  TaskBar1.OverlayIcon := Image1.Picture.Icon;
  Timer1.Enabled := True;
end;
procedure TForm1.Timer1Timer(Sender: TObject);
begin
  TaskBar1.ProgressValue := Succ(TaskBar1.ProgressValue);
  if TaskBar1.ProgressValue=100 then begin
    Timer1.Enabled := False;
    TaskBar1.OverlayIcon := nil;
  end;
end;

Go ahead and run your application again, and click it’s button.

Jump Lists.

Lets add some Jump List items.
Drop a TJumpList component and a TMemo onto your form. Set the TJumpList.ApplicationID to some value which describes your application, i.e. ‘TestJumplist’ and set the TJumpList.AutoRefresh property to True.

Now, you could add new items to the jump list using the IDE to add categories and jump list items, but this would mean that all of your items must be determined at design time. I’d rather do this in code, so that the application can decide at run-time what is appropriate to add to the jump list. Copy this code into your main forms OnCreate handler…

 

procedure TForm1.FormCreate(Sender: TObject);
var
  Category: TJumpCategoryItem;
  Item: TJumpListItem;
begin
  //- Add a custom category and two items.
  Category := JumpList1.CustomCategories.Add as TJumpCategoryItem;
  Category.CategoryName := 'Test Category';
  Item := Category.Items.Add as TJumpListItem;
  Item.FriendlyName := 'Item 1';
  Item.Arguments := 'X';
  Item := Category.Items.Add  as TJumpListItem;
  Item.FriendlyName := 'Item 2';
  Item.Arguments := 'Y';
  JumpList1.Enabled := True;
end;

This code adds a new category to the jump list, which to the user will be called ‘Test Category’, and then adds two items to the list which appear as ‘Item 1’ and ‘Item 2’ respectively. Go ahead and run your application, right click on it’s task bar icon, and you should see something like this…

One important thing to note here is that the task bar items are persistent. To illustrate, go ahead and select the “Pin to taskbar” item from this menu, and then close the application. Right click again on the task bar icon, which is now ‘pinned’ to the task bar, and you should still see the same Test Category and two items in the jump list. Selecting either of the items will start your application.

Great, but what is the use of these two items if all they do is start the application? The task bar icon it’s self can do that.  Well the purpose here is to provide context to the application as it launches. Modify your main forms OnCreate handler to read as follows…

procedure TForm1.FormCreate(Sender: TObject);
var
  Category: TJumpCategoryItem;
  Item: TJumpListItem;
  idx: uint32;
begin
  //- Add a custom category and two items.
  Category := JumpList1.CustomCategories.Add as TJumpCategoryItem;
  Category.CategoryName := 'Test Category';
  Item := Category.Items.Add as TJumpListItem;
  Item.FriendlyName := 'Item 1';
  Item.Arguments := 'X';
  Item := Category.Items.Add  as TJumpListItem;
  Item.FriendlyName := 'Item 2';
  Item.Arguments := 'Y';
  JumpList1.Enabled := True;
  //- Loop the parameters
  if ParamCount<1 then begin
    exit;
  end;
  Memo1.Lines.Clear;
  for idx := 1 to ParamCount do begin
    Memo1.Lines.Add(ParamStr(idx));
  end;
end;

Now, you’ll either need to run the application once and close it again, or hit “Project/Build” from the menu in order to rebuild the executable with the new form start-up code. Then right click on the Task Bar icon once more, and select the “Item 1” option…

The Memo control will now contain the character ‘X’, what is this you ask?  Well if you look back at the main form OnCreate handler, you’ll notice that the two items we added each have an Argument property. The argument property for Item 1 is set to X, and for Item 2 is set to Y. So when we launch the application from the “Item 1” jump-list entry, the argument ‘X’ is passed to the application on the command line. Similarly, if you launch the application again using “Item 2” you’ll see that “Y” is passed to the application…

You can now add logic to your application on start up, to determine the state in which the application should be opened.

Source Code

Source code for this post is available from my public subversion repository at: (subversion client required)
svn://public.chapmanworld.com/public/ModernizingDelphiApps/VCL/TaskIconJumpList

Conclusion.

There are additional features on the TTaskbar and TJumpList components which I invite you to explore, however, you now have the ability to use the Task Bar Icon to bring modern Windows UX features to your Delphi application.

As Always, Thanks for Reading!