Qt Support #28 – Creating a toolbar widget that is displayed with the context menu

Published Friday December 7th, 2012 | by

You have probably seen applications that have a toolbar shown with a context menu. The toolbar enables the fast use of selected set of actions. Let’s take a look how you can create such a toolbar widget with Qt.

As the toolbar widget will be connected to the context menu of the application you will naturally need one. We won’t cover here the details of creating the context menu; instead you can take a look at the Menu Example (http://qt-project.org/doc/qt-4.8/mainwindows-menus.html) to see how one can be implemented. The example is also something you can use as basis when creating the toolbar functionality with the steps explained here.

First of all we need to create a widget for the toolbar. The toolbar widget can be inherited from QWidget and we need to make sure the Qt::Popup window flag is set for the widget. Also the position of the toolbar widget is something we want to change so that it’s placed on top of the context menu. This is why the position of the context menu is passed to the constructor of the toolbar widget.

ToolBarWidget::ToolBarWidget(QPoint pos, QWidget *parent) : QWidget(parent)
{
     setWindowFlags(windowFlags() | Qt::Popup);
     createLayout();
     int newYPos = pos.y() - 50;
     move(pos.x(), newYPos);
}

We need to select the actions that we want to enable via the toolbar widget and add them to the layout of the widget. For our toolbar widget we will have a combobox and two tool buttons:

void ToolBarWidget::createLayout()
{
     QHBoxLayout *layout = new QHBoxLayout;
     QComboBox *combo = new QComboBox(this);
     combo->addItem("Select 1");
     combo->addItem("Select 2");
     layout->addWidget(combo);
     QSize iconSize(20, 20);
     QToolButton *openButton = new QToolButton;
     openButton->setIcon(style()->standardIcon(QStyle::SP_DialogOpenButton));
     openButton->setIconSize(iconSize);
     openButton->setToolTip(tr("Open File"));
     connect(openButton, SIGNAL(clicked()), this, SLOT(open()));
     layout->addWidget(openButton);
     QToolButton *quitButton = new QToolButton;
     quitButton->setIcon(style()->standardIcon(QStyle::SP_DialogCloseButton));
     quitButton->setIconSize(iconSize);
     quitButton->setToolTip(tr("Quit"));
     connect(quitButton, SIGNAL(clicked()), qApp, SLOT(quit()));
     layout->addWidget(quitButton);
     setLayout(layout);
}

Now that the toolbar widget is in place all we need to do is to show the widget whenever the context menu is shown. This can be achieved by utilizing the contextMenuEvent() method. We create the widget, make the signal-slot connections needed and show the widget with the context menu.

void MainWindow::contextMenuEvent(QContextMenuEvent *event)
{
     QMenu menu(this);
     menu.addAction(cutAct);
     menu.addAction(copyAct);
     menu.addAction(pasteAct);
     toolBarWidget = new ToolBarWidget(event->globalPos());
     connect(&menu, SIGNAL(triggered(QAction*)), toolBarWidget, SLOT(close()));
     toolBarWidget->show();
     menu.exec(event->globalPos());
}

And that gives us a context menu with a toolbar widget.

Now it’s your turn to try out, hopefully this will help you create even fancier menus. Should you have any questions related to this then if you are a customer you can always contact the Qt Support team via the Qt Support portal http://qt.digia.com/customerportal.  Happy coding!

Update, You can get the source code for the example here: http://bit.ly/QWy79A

Did you like this? Share it:

Posted in C++, Customers, Qt

30 comments to Qt Support #28 – Creating a toolbar widget that is displayed with the context menu

Ross B. says:

Sounds great. How about adding a screenshot? I’m not exactly sure what this is.

Sylvain says:

Same, I’d really like a screen shot to see the result.

Sapo Lin Zhou says:

Yep, a screenshot would be nice.

Michał says:

+1 for the screen shot

Mikalai Arapau says:

expected a screenshot as well

hardcodes says:

+1 Screenshot, please!

Maria says:

screenshot would be very nice

7 says:

7 out of total 7 comments request for a screenshot
wonder if 8 will suffice?
++

Will Stokes says:

This sounds weird. When you right click to get a context menu, along side the context menu a second floating widget will appear? Goofy. Screenshot please. In general blog posting that talk about how to accomplish UI things w/ Qt should include screenshots of the resulting behavior IMHO.

Maxim Gnidak says:

As i understand this will not gonna work in Qt 5, as in it you can’t set windows flags… or i am missing something ?

Titta Heikkala says:

You should be able to use this code also with Qt 5. I’ve just tested it and setting windows flags worked as expected

Is this something like the Office Mini Toolbar?
http://dotnet.tech.ubc.ca/CourseWiki/images/b/b7/OfficeMiniToolbarAndContextMenu.png
http://blog.beezix.com/2012/06/22/microsoft-offices-mini-toolbar-provides-some-handy-features-in-a-small-package/

The Mini Toolbar is shown on hover, though.

Titta Heikkala says:

Yes, this is similar to the Mini Toolbar. That is also shown with the right mouse click as is the context menu in this example.

BW says:

According to the code, my guess is that it should approximately look like that:


---------------------
| Select 1 |V| O X | (V: combox arrow, O: "open" icon, X: "close" icon)
---------------------

---------------
| * Cut |
| * Copy |
| * Paste |
---------------

But well, I guess I would prefer a screenshot, though :)

No says:

I want to see a damn screenshot!
Come on Qt is all about GUI, without a screenshot its an epic fail…

Max says:

its not cute without a screenshot :(

Andy Shaw says:

I hear the calls for a screenshot, we’ll try and get one sorted on Monday and updated in the post :)

chx4 says:

connect(&menu, SIGNAL(triggered(QAction*)), toolBarWidget, SLOT(close()));

can the signals and slot has different arg style?

Titta Heikkala says:

As the documentation states: ” the signature passed to the SIGNAL() macro must not have fewer arguments than the signature passed to the SLOT() macro.”
So the signature passed to the SLOT() macro can have fewer arguments than the SIGNAL() macro has. In this case the argument is something we don’t need when closing the toolBarWidget.
http://qt-project.org/doc/qt-4.8/signalsandslots.html#signals-and-slots-with-default-arguments

Titta Heikkala says:

I have now added a screenshot of the toolbar widget. Hopefully this visualizes what the idea was :)

Robin Lobel says:

What will be the precompiled binaries for Windows ?
I guess we’ll have MingW32 and MSVC2010-32, then what can we expect ? MingW64, MSVC2010-64, MSVC2012-32, MSVC2012-64 ?

Oliver Knoll says:

Nice screenshot :)

(Sorry, couldn’t resist ;) )

Saif Warsi says:

this is nice but i was wondering if there was someway that when the cursor is moved onto the non-menu items that they receive focus. what happens currently is the that you have to click away from the menu in order to make it go away and then the items in the widget will receive focus. so instead of a two step process to first hide the popup menu and then click on the desired action the widget itself can have the focus.

PM says:

Use aboutToHide signal instead
connect(&myMenu, SIGNAL(aboutToHide()), toolBarWidget, SLOT(close()));

Titta Heikkala says:

Good point.

Using aboutToHide signal would not work, because it will close the ToolBarWidget also when the widget is selected.

This will require some modifications so that the events will be handled different to the default functionality.

For the actions to directly get the event we have to make the toolbutton widgets in the ToolBarWidget member variables and implement the mouseReleaseEvent method so that it will check if the mouse was released over the buttons and then do the actions needed. There you can also close the toolbar widget when the mouse is pressed outside the menu and the toolbar widget.

Handling the events for the combobox is a bit different because the mouse release is delivered directly. We can make a wrapper for the QComboBox and check there if the release event came without the mouse press event. From this we know that the popup for the combobox needs to be shown.

With these changes you can trigger the actions needed directly. From the end of the post you can now find the source code for the example. There you can find the changes I mentioned above.

I hope this helps!

Saif Warsi says:

thanks for this. i took your original idea and made a custom toolbarwidget where you can put in multiple toolbars and the context menu is optional in that the code where this toolbarwidget is created you can create your own context menu if you wish. anyway, i generalized the toolbarwidget mouseReleaseEvent to this to allow more flexibility; you still have to have a derived combobox to get that to work properly. hope this helps someone.

if(!rect().contains(event->pos()))
hide();
else {
QWidget *widget = qApp->widgetAt(QCursor::pos());
qDebug() <metaObject()->className());

if(widget->inherits(“QToolButton”)) {
QToolButton *bt = qobject_cast(widget);

if(bt) {
QAction *act = bt->defaultAction();
act->trigger();
}
}else if(widget->inherits(“QPushButton”)) {
QPushButton *bt = qobject_cast(widget);
if(bt)
bt->click();
}
}

Sylvain says:

Thanks for the screenshot, very helpfull.
before I though you meant to put a widget in a context menu, instead of giving a tooblar widget a context menu…

Anyway thanks for sharing! :)

[...] will continue Related articles: The primary substitute teachers for punishment classroom spe Media said the experience of of Li Xiaopeng years central en Taiwan proved to be identity through the four years of the draft amendments to t sheep chaise. [...]

Commenting closed.