I would like to be able to detect any change in both the position and orientation of a toolbar which is part of a main window. The toolbar has a QPushButton
called nodes_button and is part of a main window. I am using both the default QMainWindow
and QToolBar
. nodes_button contains a QMenu
and the purpose of this whole exercise is to place the menu indicator of nodes_button in a way that visually fits the toolbar.
A default toolbar in a default main window has 5 locations where it can be places - top, bottom, left, right and floating. Based on the area where the toolbar is located it also changes its orientation to either horizontal (floating, top and bottom) or vertical (left or right).
Determining the orientation is not difficult since a toolbars actually provides QToolBar::orientation()
(for retrieving the orientation) and QToolBar::orientationChanged(Qt::Orientation)
(a signal emitted every time the orientation of the toolbar changes). Using the signal I can connect a slot like this:
connect(toolbar, SIGNAL(orientationChanged(Qt::Orientation)), this, SLOT(toolbarAdjust()));
Currently toolbarAdjust()
is triggered only when the toolbar's orientation changes however I also want to use it when the location of the toolbar changes:
void MainWindow::toolbarAdjust()
{
Qt::Orientation toolbarOrientation = toolbar->orientation();
Qt::ToolBarArea toolbarPosition = this->toolBarArea(toolbar);
if(toolbarOrientation == Qt::Horizontal) {
if(toolbarPosition == Qt::NoToolBarArea || toolbarPosition == Qt::TopToolBarArea) {
nodes->setStyleSheet("QPushButton#nodes_button::menu-indicator {image: url(:node_menu_top); subcontrol-position: bottom center; subcontrol-origin: padding; bottom: -7px}");
}
else if(toolbarPosition == Qt::BottomToolBarArea) {
nodes->setStyleSheet("QPushButton#nodes_button::menu-indicator {image: url(:node_menu_bottom); subcontrol-position: top center; subcontrol-origin: padding; top: -7px}");
}
}
else if (toolbarOrientation == Qt::Vertical) {
if(toolbarPosition == Qt::LeftToolBarArea) {
nodes->setStyleSheet("QPushButton#nodes_button::menu-indicator {image: url(:node_menu_right); subcontrol-position: left center; subcontrol-origin: padding; right: -6px;}");
}
else if(toolbarPosition == Qt::RightToolBarArea) {
nodes->setStyleSheet("QPushButton#nodes_button::menu-indicator {image: url(:node_menu_left); subcontrol-position: right center; subcontrol-origin: padding; left: -6px;}");
}
}
}
This doesn't work all the time for many reasons for example because of the fact that for both left and right / top and bottom toolbar area the orientation of the toolbar is the same - vertical / horizontal.
So I need something like
connect(this, SIGNAL(toolbarLocationChanged()), this, SLOT(toolbarAdjust()));
Using the orientation and location of the toolbar I can place my menu indicator in a way that fits the current location of the toolbar. As you can see below the orientation in a combination with the corresponding variation of the stylesheet
QPushButton#nodes_button::menu-indicator {
image: url(:node_menu_top); // bottom, right, left
subcontrol-position: bottom center; // top, right, left
subcontrol-origin: padding;
bottom: -7px // top, left, right
}
leads to
I can actually omit the whole orientation part and do the following:
void MainWindow::toolbarAdjust()
{
Qt::ToolBarArea toolbarPosition = this->toolBarArea(drawingToolBar);
switch(toolbarPosition) {
case Qt::NoToolBarArea:;
case Qt::TopToolBarArea:
nodes->setStyleSheet("QPushButton#nodes_button::menu-indicator {image: url(:node_menu_top); subcontrol-position: bottom center; subcontrol-origin: padding; bottom: -7px}");
break;
case Qt::BottomToolBarArea:
nodes->setStyleSheet("QPushButton#nodes_button::menu-indicator {image: url(:node_menu_bottom); subcontrol-position: top center; subcontrol-origin: padding; top: -7px}");
break;
case Qt::LeftToolBarArea:
nodes->setStyleSheet("QPushButton#nodes_button::menu-indicator {image: url(:node_menu_right); subcontrol-position: left center; subcontrol-origin: padding; right: -6px;}");
break;
case Qt::RightToolBarArea:
nodes->setStyleSheet("QPushButton#nodes_button::menu-indicator {image: url(:node_menu_left); subcontrol-position: right center; subcontrol-origin: padding; left: -6px;}");
break;
}
}
because of the way a toolbar behaves when you dock it/float it.
EDIT:
I found this post where a user tells the OP about QDockWidget::dockLocationChanged()
and that maybe such a functionality has been added to QToolBar
too. At the end the OP post an email which shows that such a feature has been requested. The post is from 2007...
I found that the QToolBar::topLevelChanged(bool)
signal helps me solve the problem. Whenever the user wants to change the toolbar area of a toolbar he/she has to click on the toolbar, drag it to that area and then drop it. Based on the Qt documentation:
This signal is emitted when the floating property changes. The topLevel parameter is true if the toolbar is now floating; otherwise it is false.
So whenever the user is dragging the toolbar it is obviously also floating. Once the toolbar is docked it is not floating. Detecting this change in the floating property of the toolbar can be used to adjust its contents.
Here is the result if anyone's interested:
Top placement (indicator pointing downwards)
Bottom placement (indicator pointing upwards)
Left placement (indicator pointing to the right)
Right placement (indicator pointing to the left)