QToolButton всплывающее меню только при нажатии и удержании

Я пытаюсь реализовать кнопку "Открыть" так, чтобы, если пользователь нажимает ее и удерживает, появится меню приложений, из которых пользователь может выбрать; но как только пользователь отпускает мышь, меню должно исчезнуть. если пользователь отпускает мышь, не выбирая приложение в меню, он должен открыть файл с приложением по умолчанию. Я реализую эту кнопку как QToolButton и подключите сигналы следующим образом:

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

Прямо сейчас, когда пользователь нажимает кнопку, появится меню. Тем не менее, меню все еще там, когда пользователь отпускает кнопку, и действие в меню запускается нажатием на нее. Я пробовал под обоими DelayedPopup а также InstantPopup Режим. Пока меню было установлено для self.ui_open_btnЯ больше не могу поймать released сигнал. Как я могу скрыть меню, когда пользователь отпускает мышь? Как действие в меню может быть вызвано отпусканием мыши?

--added ---

Я нашел еще одну проблему с использованием QToolButton: меню всегда появляется при нажатии кнопки. Вместо этого я хотел бы поймать pressed сигнал, сделайте некоторую проверку, чтобы определить, должно ли всплывающее меню или нет. Поэтому я изменил свой подход к написанию своей настраиваемой кнопки инструментов путем создания подклассов QPushButton а также QMenu, Пожалуйста, смотрите мой код в ответе ниже.

Благодарю.

2 ответа

Решение

Мне удалось достичь того, что я хочу, путем подклассов QPushButton а также 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)

и в QDialog содержащий эту кнопку, я делаю следующее:

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

Создайте пользовательский QToolButton, который будет фильтровать события из меню и реагировать на событие отпускания мыши, полученное меню:

class MyToolButton(QtGui.QToolButton):
    def __init__(self, *args):
        QtGui.QToolButton.__init__(self, *args)
    def eventFilter(self, menu, event):
        if event.type() == QtCore.QEvent.MouseButtonRelease:
            if self.underMouse():
                menu.close()
                # and now do default action
                print "doing default action"
                return True
        return False

Установите фильтр событий после того, как вы установили меню:

self.ui_open_btn.menu().installEventFilter(self.ui_open_btn)
Другие вопросы по тегам