Toolbar button with drop down menu

by The Rabbit   Last Updated August 13, 2019 20:22 PM

I want to create my own Toolbar with a Toolbar button which has a drop down menu:

The following code works fine in the QGIS console:

from qgis.core import Qgis
from PyQt5.QtWidgets import QToolBar,QMenu,QToolButton,QPushButton,QAction

def findActionByObjectName(objname,iface):
    try:
        toolbars = iface.mainWindow().findChildren(QToolBar)
        for toolbar in toolbars:
            for action in toolbar.actions():
                if action.objectName():
                   if action.objectName().lower() == objname.lower(): return action
                if action.actionGroup() is not None:
                    for a in action.actionGroup().actions():
                        if a.objectName():
                            if a.objectName().lower() == objname.lower(): return a
        menubar = iface.mainWindow().menuBar()
        for action in menubar.actions():
            if action.menu():
                for action in action.menu().actions():
                    if action.menu():
                        for a in action.menu().actions():
                            if a.objectName():
                                if a.objectName().lower() == objname.lower(): return a
                    else:
                        if action.objectName():
                            if action.objectName().lower() == objname.lower(): return action
            else:
                if action.objectName():
                    if action.objectName().lower() == objname.lower(): return action
    except Exception as e:
        print(e)

toolbar = iface.mainWindow().findChild(QToolBar,'Test')
if not toolbar:
    toolbar = QToolBar()
    toolbar.setObjectName('Test')
    toolbar.setWindowTitle("TEST")
    iface.addToolBar(toolbar)

actionlist = ["mActionMeasure","mActionMeasureArea","mActionMeasureAngle"]
stdAction =None
menu = QMenu()
for name in actionlist:
    action = findActionByObjectName(name,iface)
    if action:
        print ('found:',action.objectName()) 
        menu.addAction(action)

stdAction=QAction("Measure")
stdAction.setMenu(menu)
toolbar.addAction(stdAction)

When it runs from my plugin, it creates the toolbar, but not the button with the menu?

Tags : pyqgis-3 pyqt


Answers 1


from PyQt5.QtWidgets import QWidget, QToolBar,QMenu,QToolButton,QPushButton,QSizePolicy

def addAction(widget, actionNameOrList,parent=None):
    try:
        if isinstance(actionNameOrList, str):
            tname = actionNameOrList.lower()
            if tname == "|":
                widget.addSeparator()
            else:
                action = iface.mainWindow().findChild(QAction,actionNameOrList)
                if action is not None:
                    widget.addAction(action)
                else:
                    widget.addWidget(QLabel(actionNameOrList,parent))
        elif isinstance(actionNameOrList, list):
            widget.addWidget(createToolButton(actionNameOrList,parent))
    except Exception as e:
        info(e)

def createToolButton( actionNamesList, parent=None):
    try:
        menu = QMenu(parent)
        for an in actionNamesList:
            addAction(menu,an,parent)
            actions = [a for a in menu.actions()]
        tb = QToolButton()
        tb.setDefaultAction(actions[0])
        tb.setMenu(menu)
        tb.setPopupMode(QToolButton.MenuButtonPopup)
        menu.triggered.connect(tb.setDefaultAction)
        return tb
    except Exception as e:
        info(e)

def info(*args):
    print(args)

try:    
    tb_name = "mytb_test"
    tb = iface.mainWindow().findChild(QToolBar,tb_name) 
    if tb is None:#create the toolbar
        tb = QToolBar(iface.mainWindow())
        tb.setObjectName(tb_name)
        tb.setWindowTitle("My Toolbar")
        iface.mainWindow().addToolBarBreak()#toolbar in new line
        iface.addToolBar(tb)
    else:
        tb.clear()
    #add actions to tb
    actionsList =["MyAPp:","mActionSaveProject","|","mActionZoomIn","mActionZoomOut",["mActionMeasure","mActionMeasureAngle","mActionMeasureArea"]]
    for a in actionsList:
        addAction(tb,a)
    #add a hide button
    btnObjectName = 'mClose_' + tb_name
    btn = tb.findChild(QPushButton, btnObjectName)
    if btn is None:
        btnHide = QPushButton()
        btnHide.setObjectName(btnObjectName)
        btnHide.setMaximumWidth(15)
        btnHide.setToolTip('close')
        btnHide.clicked.connect(lambda: tb.setHidden(True))
        #spacer
        spacer = QWidget()
        spacer.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
        tb.addWidget(spacer)
        tb.addWidget(btnHide)
    tb.show()
except Exception as e:
    info(e)
    enter code here
The Rabbit
The Rabbit
August 13, 2019 19:18 PM

Related Questions


Updated September 04, 2018 13:22 PM

Updated June 13, 2015 09:09 AM

Updated July 28, 2017 23:22 PM

Updated December 10, 2017 16:22 PM