I'm currently trying to create quite a lot of contextMenu for lots of different buttons in a maya UI I'm working on.
The issue is that I've a long list of buttons and I need the same contextMenu for all of them. What I'm doing now is not really elegant, that's why I'm asking if you could help me.
Because with the following process, my script will be long, but I can't figure out how to clean that properly.
Here's an example of my code :
from PyQt4 import QtCore,QtGui,uic
from functools import partial
import os
class MyWidget(QtGui.QWidget):
def __init__(self, parent=None):
QtGui.QWidget.__init__(self, parent)
uiFilePath = os.path.join(os.path.dirname(__file__),"myfile.ui")
self.ui = uic.loadUi(uiFilePath, self)
'''
Right Click Menu
'''
self.ui.buttonA.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
self.ui.buttonA.customContextMenuRequested.connect(self.buttonAMenu)
self.ui.buttonB.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
self.ui.buttonB.customContextMenuRequested.connect(self.buttonBMenu)
'''
BUTTON A
'''
@QtCore.pyqtSlot()
def on_buttonA_released(self):
print ('Doing Stuff when clicking on Button A')
def buttonAMenu(self, pos):
menu = QtGui.QMenu()
menu.addAction('First Action', lambda:self.FirstActionButtonA(objects))
menu.addAction('Second Action', lambda:self.SecondActionButtonA(objects))
menu.exec_(QtGui.QCursor.pos())
def FirstActionButtonA(self, objects):
print ('First Action working on :')
print (objects)
def SecondActionButtonA(self):
print ('Second Action working on :')
print (objects)
'''
BUTTON B
'''
@QtCore.pyqtSlot()
def on_buttonB_released(self):
print ('Doing Stuff when clicking on Button B')
def buttonBMenu(self, pos):
menu = QtGui.QMenu()
menu.addAction('First Action', lambda:self.FirstActionButtonB(objects))
menu.addAction('Second Action', lambda:self.SecondActionButtonB(objects))
menu.exec_(QtGui.QCursor.pos())
def FirstActionButtonB(self, objects):
print ('First Action working on :')
print (objects)
def SecondActionButtonB(self):
print ('Second Action working on :')
print (objects)
So what you want to do is create a class which contains your code. You can create an instance of this class for each button or instead of each button. The two options are:
QPushButton
and promote your buttons in Qt Designer to your new classNote that the preferred solution is to subclass QPushButton
and then promote your widgets in Qt Designer to your new class. However, this can be a bit fiddly to work out. But, if you want to go down this route, you can, and you'll want to read this: Promote PyQt Widget
The class will look similar either way. You'll want something like this (for option 1)
class MyButton(object):
def __init__(self, button):
self.button = button
self.button.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
self.button.customContextMenuRequested.connect(self.buttonMenu)
self.button.clicked.connect(self.on_button_released)
@QtCore.pyqtSlot()
def on_button_released(self):
print ('Doing Stuff when clicking on Button A')
def buttonMenu(self, pos):
menu = QtGui.QMenu()
menu.addAction('First Action', lambda:self.FirstActionButton(objects))
menu.addAction('Second Action', lambda:self.SecondActionButton(objects))
menu.exec_(QtGui.QCursor.pos())
def FirstActionButton(self, objects):
print ('First Action working on :')
print (objects)
def SecondActionButton(self):
print ('Second Action working on :')
print (objects)
Your MyWidget
class would then look like:
class MyWidget(QtGui.QWidget):
def __init__(self, parent=None):
QtGui.QWidget.__init__(self, parent)
uiFilePath = os.path.join(os.path.dirname(__file__),"myfile.ui")
self.ui = uic.loadUi(uiFilePath, self)
list_of_buttons = [self.ui.buttonA, self.ui.buttonB,...]
self.adaptors = []
for button in list_of_buttons:
self.adapters.append(MyButton(button))
For option 2, you'll want to change your class to be like this:
class MyButton(QtGui.QPushButton):
def __init__(self, *args, **kwargs):
QPushButton.__init__(self,*args,**kwargs)
self.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
self.customContextMenuRequested.connect(self.buttonMenu)
self.clicked.connect(self.on_button_released)
# same code follows as in above class example
If widget promotion is done correctly, you won't need to do anything special in the __init__
method of the MyWidget
class as your custom class will be instantiated automatically when you call uic.loadUI
.