QWidgetAction for QToolButtons on secondary toolbar
-
In my application I use toolbars not only in the QMainWindow, but also in some dock widgets. According to the Qt documentation¸ for proper handling of QToolButtons/QActions in secondary toolbars, these buttons/actions should be subclasses of QWidgetAction.
When a QToolBar is not a child of a QMainWindow, it loses the ability to populate the extension pop up with widgets added to the toolbar using addWidget(). Please use widget actions created by inheriting QWidgetAction and implementing QWidgetAction::createWidget() instead.
I tried to implement my subclass as
#ifndef TOOLBUTTONACTION_H #define TOOLBUTTONACTION_H #include <QMenu> #include <QPointer> #include <QToolButton> #include <QWidgetAction> class ToolButtonAction : public QWidgetAction { Q_OBJECT public: explicit ToolButtonAction( QObject *parent = nullptr ); void setAutoRaise( bool autoRaise ); void setPopupMode( QToolButton::ToolButtonPopupMode mode ); void setToolButtonStyle( Qt::ToolButtonStyle style ); void setMenu( QMenu *menu ); void addActions( const QList<QAction *> &actions ); void setDefaultAction( QAction *action ); QAction *defaultAction() const; protected: QWidget *createWidget( QWidget *parent ) override; void deleteWidget( QWidget *widget ) override; private: void applyState( QToolButton *button ) const; private: bool mAutoRaise = false; Qt::ToolButtonStyle mToolButtonStyle = Qt::ToolButtonStyle::ToolButtonIconOnly; QToolButton::ToolButtonPopupMode mPopupMode = QToolButton::ToolButtonPopupMode::DelayedPopup; QPointer< QMenu > mMenu; QList< QAction * > mButtonActions; QPointer< QAction > mDefaultAction; QPointer< QToolButton > mButton; }; #endif // TOOLBUTTONACTION_Hand
#include "toolbuttonaction.h" #include <QMenu> #include <QToolBar> ToolButtonAction::ToolButtonAction( QObject *parent ) : QWidgetAction( parent ) { } void ToolButtonAction::setAutoRaise( bool autoRaise ) { mAutoRaise = autoRaise; if ( mButton ) { mButton->setAutoRaise( autoRaise ); } } void ToolButtonAction::setPopupMode( QToolButton::ToolButtonPopupMode mode ) { mPopupMode = mode; if ( mButton ) { mButton->setPopupMode( mode ); } } void ToolButtonAction::setToolButtonStyle( Qt::ToolButtonStyle style ) { mToolButtonStyle = style; if ( mButton ) { mButton->setToolButtonStyle( style ); } } void ToolButtonAction::setMenu( QMenu *menu ) { mMenu = menu; if ( mButton ) { mButton->setMenu( menu ); } } void ToolButtonAction::addActions( const QList< QAction * > &actions ) { for ( QAction *action : std::as_const( actions ) ) { mButtonActions.append( action ); } if ( mButton ) { mButton->addActions( actions ); } } void ToolButtonAction::setDefaultAction( QAction *action ) { if ( !action ) { return; } mDefaultAction = action; if ( mButton ) { mButton->setDefaultAction( action ); } } QAction *ToolButtonAction::defaultAction() const { return mDefaultAction; } QWidget *ToolButtonAction::createWidget( QWidget *parent ) { QToolButton *button = new QToolButton( parent ); button->setAutoRaise( mAutoRaise ); button->setPopupMode( mPopupMode ); button->setToolButtonStyle( mToolButtonStyle ); if ( QToolBar *toolBar = qobject_cast< QToolBar * >( parent ) ) { button->setIconSize( toolBar->iconSize() ); connect( toolBar, &QToolBar::iconSizeChanged, button, &QToolButton::setIconSize ); button->setToolButtonStyle( toolBar->toolButtonStyle() ); connect( toolBar, &QToolBar::toolButtonStyleChanged, button, &QToolButton::setToolButtonStyle ); } if ( mMenu ) { button->setMenu( mMenu ); } if ( !mButtonActions.isEmpty() ) { button->addActions( mButtonActions ); } if ( mDefaultAction ) { button->setDefaultAction( mDefaultAction ); } else { applyState( button ); connect( button, &QToolButton::clicked, this, &QAction::trigger ); } mButton = button; return button; } void ToolButtonAction::deleteWidget( QWidget *widget ) { QWidgetAction::deleteWidget( widget ); } void ToolButtonAction::applyState( QToolButton *button ) const { button->setEnabled( isEnabled() ); if ( !mDefaultAction ) { button->setIcon( icon() ); button->setText( text() ); button->setToolTip( toolTip() ); } }This works, but I'm not sure I correctly understand and handle case when the same button/action is added in different places, e.g. to the main toolbar/menu and secondary toolbar. Should I keep track of created buttons in my subclass, e.g. to change their properties like autoraise/popup mode/etc. or returning a single widget is enough? My understanding is that
createWidget()is called once per container to which I add action. So when for example I add action to a toolbar and then shrink it, a new action is also created for extension popup and I will end up with two actions. Am right?If my understanding is correct, I will need to replace
QPointer< QToolButton > mButton;withQList< QPointer< QToolButton > > mButtons;and then in all setters do something likefor ( QToolButton *button : std::as_const( mButtons ) ) { if ( button ) { button->setAutoRaise( autoRaise ); } } -
Hi,
From a quick look at the implementation of QWidgetAction, you should:
- nuke
mButtoncompletely (requestWidget calls createWidget and builds the list of all widgets created) - in your various setters call createdWidgets and apply there the changes that were done to all the buttons that have been created.
- nuke