In this tutorial I'll explain how to create a Windows 7 thumbnail toolbar using Qt with MINGW GCC. At the end of the post you'll find the link to the project's code.
Missing definitions and declarations
MINGW GCC doesn't have all needed definitions and declarations to create a windows 7 thumbnail toolbar. That is why they need to be defined. I've explained how I did it in my previous
post. You can browse the definitions file
here.
Project settings
It is needed to add extra linkage libraries options to the linker.
LIBS += libcomctl32 libole32
Creating the thumbnail toolbar
In short you need to do the following:
1) Create an instance to the ITaskbarList3 COM interface
2) Create a list of images and add it to the thumbnail toolbar
3) Create a list of thumbnail toolbar buttons and add it to the toolbar
4) Update the buttons or the images when needed
What you can do:
1) Show/hide, disable/enable, change button details, update the image list
2) Have a thumbnail toolbar per program's window
What you can't do:
1) Add more than 7 buttons to the toolbar
2) Remove the toolbar (it will be destroyed when the window associated to it will be destroyed.)
Initialize the ITaskbarList3 COM interface
Firstly you need to implement your own winEvent function. This can be done by overriding the QMainWindow's winEvent protected function.
class MainWindow : public QMainWindow
{
//...
protected:
bool winEvent(MSG * message, long * result);
//...
};
In order to initialize the ITaskbarList3 COM interface it is needed to register the
"TaskbarButtonCreated" event.
//..
unsigned int messageId = RegisterWindowMessage(L"TaskbarButtonCreated");
//..
When the event is registered, it is possible to obtain access to ITaskbarList3.
Putting all together:
//...
bool MainWindow::winEvent(MSG * message, long * result)
{
static UINT taskBarCreatedId = WM_NULL;
if (taskBarCreatedId == WM_NULL) {
taskBarCreatedId = RegisterWindowMessage(L"TaskbarButtonCreated");
}
if (message->message == taskBarCreatedId) {
//initialize the ITaskbarList3 interface
}
return false;
}
Initializing the Interface
//..
void MainWindow::W7ToolbarInit() {
HRESULT hr = CoCreateInstance(CLSID_TaskbarList, NULL, CLSCTX_INPROC_SERVER, IID_ITaskbarList3,
reinterpret_cast<void**> (&(m_w7toolbar)));
if (SUCCEEDED(hr)){
hr = m_w7toolbar->HrInit();
if (FAILED(hr)) {
m_w7toolbar->Release();
m_w7toolbar = NULL;
}
}
}
//..
Create the list of images
The images I used in the project were PNG files 20x20 pixels, 32 bit, with transparency.
Create the image list to hold 4 images:
HIMAGELIST himl = ImageList_Create(20, 20, ILC_COLOR32, 4, 0);
Add the images to the list:
QPixmap img;
QBitmap mask;
img = QIcon(":/back.png").pixmap(20);
mask = img.createMaskFromColor(Qt::transparent);
ImageList_Add(himl, img.toWinHBITMAP(QPixmap::PremultipliedAlpha), mask.toWinHBITMAP());
//repeat the same thing for the rest of the images
Set the thumbnailtoolbar's image list to the :
m_w7toolbar->ThumbBarSetImageList(this->winId(), himl);
"this" is a pointer to a QMainWindow object, but it also can be a QWidget pointer.
Free the allocated memory:
ImageList_Destroy(himl);
Add the buttons
Each button structure holds information about the button. Such as image index, the index from the image list, tool tip text, state, visibility and other flags.
It is important to remember, the thumbnail toolbar can't hold more than 7 buttons.
Let's say we want to have three buttons:
class MainWindow : public QMainWindow
{
//..
THUMBBUTTON m_thbButtons[3];
//..
};
Initializing and adding the buttons:
#define IDTB_FIRST 3000
void MainWindow::W7ToolbarButtonsInit() {
QString tooltips[3] = {"Prev", "Play", "Next"};
for (int index = 0; index < 3; index++) {
wcscpy(m_thbButtons[index].szTip, tooltips[index].toStdWString().c_str());
//the ID of the button
m_thbButtons[index].iId = IDTB_FIRST + index;
//the image of the button, index from the image list
m_thbButtons[index].iBitmap = index;
//show tooltip and use the bitmpap index
m_thbButtons[index].dwMask = (THUMBBUTTONMASK)(THB_BITMAP | THB_FLAGS | THB_TOOLTIP);
//set the button enabled
m_thbButtons[index].dwFlags = (THUMBBUTTONFLAGS)(THBF_ENABLED);
}
//set the buttons
m_w7toolbar->ThumbBarAddButtons(this->winId(), 3, m_thbButtons);
}
Once the buttons are added, they should be visible.
Catching the thumbnailtoolbar click events
When a button is pressed, an event with the button's id is generated. These events can be caught in the winEvent function.
//...
bool MainWindow::winEvent(MSG * message, long * result)
{
static UINT taskBarCreatedId = WM_NULL;
if (taskBarCreatedId == WM_NULL) {
taskBarCreatedId = RegisterWindowMessage(L"TaskbarButtonCreated");
}
if (message->message == taskBarCreatedId) {
W7ToolbarInit();
W7ToolbarSetImages();
W7ToolbarButtonsInit();
} else switch (message->message){
case WM_COMMAND:
{
//get the button index
int buttonId = LOWORD(message->wParam) - IDTB_FIRST;
if ((buttonId >= 0) && (buttonId < 3)) {
qDebug() << "Button " << buttonId << " was pressed";
if (buttonId == 1) { //if "Play|Pause" was pressed
if (m_thbButtons[1].iBitmap == 1) {
//set the Pause image index
m_thbButtons[1].iBitmap = 3;
wcscpy(m_thbButtons[1].szTip, L"Pause");
} else {
//set the Play image index
m_thbButtons[1].iBitmap = 1;
wcscpy(m_thbButtons[1].szTip, L"Play");
}
//update the thumbnailtoolbar
m_w7toolbar->ThumbBarUpdateButtons(this->winId(), 3, m_thbButtons);
}
}
break;
}
default:
return false;
}
return false;
}
The code can be downloaded from
here.
The screenshot can be seen below: