QAction切换受到QMenu mousePressEvent的阻碍 [英] QAction toggling is hinder by QMenu mousePressEvent

查看:380
本文介绍了QAction切换受到QMenu mousePressEvent的阻碍的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个嵌套菜单项,我试图在其中使所有菜单项都可检查.最初,切换不适用于主要项目(设置为QAction的QMenu),而适用于子项目.

I have a nested menu items in which I am trying to make all of the items checkable. Initially the toggling is not working for the main item (a QMenu that is set as a QAction), while it works for sub items.

但是使用mousePressEvent时,切换现在适用于主要项目,但不适用于子项目.

But upon the use of mousePressEvent, the toggling now works for the main item but not for the sub items.

试图为子项功能复制我对主项所做的操作,但是切换仍然不起作用.貌似,它在_callActionItem()中被调用了两次.

Tried to replicate what I have done for main item for the sub item function, but the toggling still does not work. And seemingly, it is called twice in the _callActionItem().

但是,由于某些原因,如果子项目窗口处于撕下"模式,则可以切换,但如果您在工具本身中单击鼠标右键,则无法切换.

However, for some reasons, if the sub-item window is in tear off mode, toggling is possible but not so, if you do a right click menu in the tool itself.

另外,如果我在QCustomMenu中禁用了mousePressEvent,我将回到第一个方框,在该方框中,子项可切换,但主项不起作用

Additionally, if I disable mousePressEvent in QCustomMenu, I am back to square one where toggling works for sub-items but not the main-items

class QSubAction(QtGui.QAction):
    def __init__(self, text="", parent=None):
        super(QSubAction, self).__init__(text, parent)
        self.setCheckable(True)
        self.setChecked(True)


class QAddAction(QtGui.QAction):
    def __init__(self, icon=None, text="Add Item", parent=None):
        if icon:
            super(QAddAction, self).__init__(icon, text, parent)
        else:
            super(QAddAction, self).__init__(text, parent)

class QCustomMenu(QtGui.QMenu):
    """Customized QMenu."""

    def __init__(self, title, parent=None):
        super(QCustomMenu, self).__init__(title=str(title), parent=parent)
        self.setup_menu()

    def mousePressEvent(self, event):
        action = self.activeAction()
        if isinstance(action, QtGui.QAction):
            action.trigger()
        return QtGui.QMenu.mousePressEvent(self, event)

    def setup_menu(self):
        self.setContextMenuPolicy(QtCore.Qt.DefaultContextMenu)

    def contextMenuEvent(self, event):
        no_right_click = [QAddAction]
        if any([isinstance(self.actionAt(event.pos()), instance) for instance in no_right_click]):
            return
        pos = event.pos()

    def addAction(self, action):
        super(QCustomMenu, self).addAction(action)


class Example(QtGui.QMainWindow):
    def __init__(self, parent=None):
        super(Example, self).__init__(parent)
        self.initUI()

    def initUI(self):         
        self.setGeometry(300, 300, 300, 200)
        self.setWindowTitle('Context menu')   

        self.qmenu = QCustomMenu(title='', parent=self)
        add_item_action = QtGui.QAction('Add Main item', self,
            triggered=self.add_new_item)
        self.qmenu.addAction(add_item_action)

    def contextMenuEvent(self, event):
        action = self.qmenu.exec_(self.mapToGlobal(event.pos()))

    def add_new_item(self):
        main_menu_name, ok = QtGui.QInputDialog.getText(
            self,
            'Main Menu',
            'Name of new Menu Item:'
        )
        if ok:
            self._addMenuItemTest(main_menu_name)

    def _addMenuItemTest(self, main_menu_name):
        icon_path = '/user_data/add.png'

        base_qmenu = QCustomMenu(title=main_menu_name, parent=self)
        base_qmenu.setTearOffEnabled(True)                     

        add_item_action = QAddAction(None, 'Add Sub Item', base_qmenu)
        slot = functools.partial(self.add_sub_item, base_qmenu)
        add_item_action.triggered.connect(slot)
        base_qmenu.addAction(add_item_action)

        test_action = QtGui.QAction(main_menu_name, self)
        test_action.setMenu(base_qmenu)
        test_action.setCheckable(True)
        test_action.setChecked(True)

        self.connect(
            test_action,
            QtCore.SIGNAL("triggered(bool)"),
            self.main_toggling
        )

        self.qmenu.addAction(test_action)

    def main_toggling(self, check_state):
        sender_obj = self.sender()
        if isinstance(sender_obj, QtGui.QAction):
            sender_obj.setChecked(check_state)

    def add_sub_item(self, base_menu):
        sub_menu_name, ok = QtGui.QInputDialog.getText(
            self,
            'Sub Menu',
            'Name of new Sub Item:'
        )
        if ok:
            action = QSubAction(sub_menu_name, self)
            slot = functools.partial(
                self._callActionItem,
                action
            )
            # action.toggled.connect(slot)
            # from pprint import pprint
            # pprint(help(action))
            # action.connect(action, QtCore.SIGNAL("triggered(bool)"), self._callActionItem)

            base_menu.addAction(action)

    def _callActionItem(self, action):
        # This is called twice, False and True again
        print '>>> sub check-state : ', action.isChecked()


if __name__ == "__main__":
    app = QtGui.QApplication(sys.argv)
    window = Example()
    window.show()
    sys.exit(app.exec_())

推荐答案

默认情况下,QMenu只会使没有子级的QAction可以进行检查,因此您做了一个技巧来启用另一个不满足上述要求的QAction的功能.可能会影响操作,这就是您所遇到的情况.解决方案是区分按下了哪种类型的QAction:

By default QMenu will only make the QAction without children can check, so you have done a trick to enable the functionality of another QAction that does not meet the above that may affect the operation, and that is what happens in your case. The solution is to discriminate which type of QAction is pressed:

def mousePressEvent(self, event):
    action = self.activeAction()
    if not isinstance(action, QSubAction) and action is not None:
        action.trigger()
        return
    return QtGui.QMenu.mousePressEvent(self, event)

这篇关于QAction切换受到QMenu mousePressEvent的阻碍的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆