Attach a menu onto QPushButton

Hi all, I would like to attach a ‘menu’ when user left-mouse click onto the QPushButton.
Not sure if there are any things that I am suppose to keep a lookout for when integrating/ using Maya and PyQt stuff…

While I tried my code as follows, it works:

cmds.window()
geos = cmds.ls(geometry = 1, visible =1)
createdGeos = cmds.listRelatives(geos, parent=1)
    
cmds.popupMenu(button=1)
for geo in createdGeos:
    cmds.menuItem(geo)
        
cmds.showWindow()

However as soon as I tried integrating into this UI of mine, it is not working:

from PyQt4.QtCore import *
from PyQt4.QtGui import *

class geoUI(QDialog):
    def __init__(self, parent=None):
        super(geoUI, self).__init__(parent)
        self.resize(300,225)
        self.initUI()

    def initUI(self):
        self.setWindowTitle('Geo UI')
        
        self.getCurrentGeoBtn = QPushButton('Get current geo')
        self.currentGeoTxt = QLineEdit()
        
        gridLayout = QGridLayout()
        gridLayout.addWidget(self.getCurrentGeoBtn, 0, 1)
        gridLayout.addWidget(self.currentGeoTxt, 0, 2)
        
        self.setLayout(gridLayout)
        
    def createConnections(self):
        self.connect(self.getCurrentGeoBtn, SIGNAL('clicked()'), self.getGeo)

    def getGeo(self):        
        geos = cmds.ls(geometry = 1, visible =1)
        createdGeos = cmds.listRelatives(geos, parent=1)
    
        cmds.popupMenu(button=1)
        for geo in createdGeos:
            cmds.menuItem(geo)


        
def main():
    global app 
    global form
    app = qApp
    form = geoUI()
    form.show()
    

if __name__ == '__main__':
    main() 

Any advice?

Many thanks in advance!

I could be wrong, but I don’t think you can mix and match Maya’s UI widgets with Qt’s. You need to attached a QMenu to the QButton, and fill out the QMenu with QActions.

to elaborate on rgkovach, instead of cmds.popupMenu, use QMenu(), and add QActions to it instead of cmds.menuItem(). Then use QPushButton.setMenu(menu)

wow, it seems like I have stumbled upon something profound. I thought using SIP will be the solution…

Hi TheMaxx, I am doing something similar as the TS. But could you kindly elaborate the method?
I am slightly confused about the QActions and the QPushButton.setMenu(menu)

[QUOTE=salik89;25311]Hi TheMaxx, I am doing something similar as the TS. But could you kindly elaborate the method?
I am slightly confused about the QActions and the QPushButton.setMenu(menu)[/QUOTE]

So the menu object needs to be created first and it will take QActions as menu items. And to access what happens when the action is triggered, make the QActions first:


action_a = QtGui.QAction('A')
action_b = QtGui.QAction('B')

menu = QtGui.QMenu()
menu.addAction(action_a)
menu.addAction(action_b)

button = QtGui.QPushButton('my button')
button.setMenu(menu)

In this example, the potential of the actions are not utilized, but fulfil the use as menu items. You can create a set of QActions for an app, then insert them into many different menus and toolbars (even make buttons out of them) and then you can enable/disable them once and the rest of the UI is updated.

[QUOTE=TheMaxx;25316]So the menu object needs to be created first and it will take QActions as menu items. And to access what happens when the action is triggered, make the QActions first:

In this example, the potential of the actions are not utilized, but fulfil the use as menu items. You can create a set of QActions for an app, then insert them into many different menus and toolbars (even make buttons out of them) and then you can enable/disable them once and the rest of the UI is updated.[/QUOTE]

Hmm, I am getting quite some errors such as the instancemethod in the QMenu.addAction etc. Not sure if I did it wrong.

def initUI(self):       
    self.setCameraBtn = QPushButton()
    self.setCameraBtn.setMenu(self.pop_file_menu())

def pop_file_menu(self):
        aMenu = QMenu()
        aMenu.addAction(self.fileOpenAct)

 def createConnections(self): 
        self.fileOpenAct = self.connect(self.setCameraBtn, SIGNAL('clicked()'), self.testMenu)

def fileOpenAct(self):
        camLs = cmds.ls(visible = 1, type = 'camera')
        camLsMenu = cmds.listRelatives(camLs, p=1)
        self.setCameraBtn.setMenu(camLsMenu)

These are the errors:

# TypeError: arguments did not match any overloaded call:
#   QMenu.addAction(QAction): argument 1 has unexpected type 'instancemethod'
#   QMenu.addAction(QString): argument 1 has unexpected type 'instancemethod'
#   QMenu.addAction(QIcon, QString): argument 1 has unexpected type 'instancemethod'
#   QMenu.addAction(QString, QObject, SLOT(), QKeySequence shortcut=0): argument 1 has unexpected type 'instancemethod'
#   QMenu.addAction(QString, callable, QKeySequence shortcut=0): argument 1 has unexpected type 'instancemethod'
#   QMenu.addAction(QIcon, QString, QObject, SLOT(), QKeySequence shortcut=0): argument 1 has unexpected type 'instancemethod'
#   QMenu.addAction(QIcon, QString, callable, QKeySequence shortcut=0): argument 1 has unexpected type 'instancemethod' # 
  • fileOpenAct isnt an action, its a function, that is being redefined in createConnections
  • You need to make QActions, then connect their ‘triggered’ signals to your call back
  • pop_file_menu doesn’t return anything

See my example from above

In that case, should I defined all these qmenu and qactions etc within a function, maybe inside my initUI, or defined it seperately?

when i make a widget, i usually have a method in there that handles all the event connections, sometimes i’ll put actions into here. If it makes sense, use the designer for your widget.