I'm trying to implement an "open" button such that if a user presses it and holds, a menu of applications for the user to choose from will pop up; but as soon as the user releases the mouse, the menu should disappear. if the user releases the mouse without choosing an application on the menu, it should open the file with the default application. I'm implementing this button as a QToolButton
and connect the signals as follows:
self.ui_open_btn.pressed.connect(self._onOpenBtnPressed)
self.ui_open_btn.triggered.connect(self._onOpenBtnTriggered)
def _onOpenBtnPressed(self):
self.ui_open_btn.showMenu()
def _onOpenBtnTriggered(self, action):
application_name = action.text()
# code to launch the application
Right now, when the user presses the button, the menu will pop up. However, the menu is still there when the user release the button, and action on the menu is triggered by clicking on it. I tried under both DelayedPopup
and InstantPopup
mode. As long as the menu has been set for self.ui_open_btn
, I can no longer catch any released
signal. How can I hide the menu when the user releases the mouse? How can the action on the menu be triggered by releasing the mouse?
--added---
I found another problem about using QToolButton
: the menu always pops up when the button is pressed. Instead, I would like to catch the pressed
signal, do some check to determine if the menu should pop up or not. So I changed my approach to write my customized toolbutton by subclassing QPushButton
and QMenu
. Please see my code posed in the answer below.
Thanks.
I managed to achieve what I want by subclassing QPushButton
and QMennu
:
class MyMenu(QtGui.QMenu):
""" Custom menu which will close when mouse is released. ""'"
def mouseReleaseEvent(self, event):
action = self.actionAt(event.pos())
self.triggered.emit(action)
self.close()
class MyButton(QtGui.QPushButton):
triggered = QtCore.pyqtSignal("QAction")
def __init__(self, menu=None, parent=None):
super(MyButton, self).__init__(parent)
self.setMenu(menu)
def menu(self):
return self._menu
def setMenu(self, menu):
self._menu = menu if menu else MyMenu(self)
self._menu.triggered.connect(self.triggered.emit)
and in the QDialog
containing this button, I do the following:
menu = MyMenu(self)
# insert here code to add actions to menu
self.open_btn = MyButton(parent=self, menu=menu)
self.open_btn.pressed.connect(self._onOpenBtnPressed)
self.open_btn.triggered.connect(self._onOpenBtnTriggered)
def _onOpenBtnPressed(self):
# insert here code to check whether we should pop up the menu
pos = self.mapToGlobal(self.open_btn.pos())
pos.setY(pos.y() + self.open_btn.height())
self.open_btn.menu().move(pos)
self.open_btn.menu().show()
def _onOpenBtnTriggered(self, action):
if action:
application_name = str(action.text())
# insert here code to launch this application
else:
# insert here code to launch the default application
self.close() # close this dialog