Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. QWidgetAction for QToolButtons on secondary toolbar
Qt 6.12 LTS is out! See what's new in the release blog

QWidgetAction for QToolButtons on secondary toolbar

Scheduled Pinned Locked Moved Unsolved General and Desktop
qwidgetactionqtoolbargui
2 Posts 2 Posters 61 Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • V Offline
    V Offline
    voltron
    wrote last edited by
    #1

    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_H
    

    and

    #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; with QList< QPointer< QToolButton > > mButtons; and then in all setters do something like

      for ( QToolButton *button : std::as_const( mButtons ) )
      {
        if ( button )
        {
          button->setAutoRaise( autoRaise );
        }
      }
    
    1 Reply Last reply
    0
    • SGaistS Offline
      SGaistS Offline
      SGaist
      Lifetime Qt Champion
      wrote last edited by
      #2

      Hi,

      From a quick look at the implementation of QWidgetAction, you should:

      • nuke mButton completely (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.

      Interested in AI ? www.idiap.ch
      Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

      1 Reply Last reply
      0

      • Login

      • Login or register to search.
      • First post
        Last post
      0
      • Categories
      • Recent
      • Tags
      • Popular
      • Users
      • Groups
      • Search
      • Get Qt
      • Unsolved