QAction无法检查

时间:2019-04-02 01:02:17

标签: python pyqt qmenu

我正在将(嵌套菜单)QMenu对象“转换”为QAction(使用setMenu),以便我可以在其上切换复选框,但是无法切换该复选框,它保持选中状态。 / p>

import functools
import sys
from PyQt4 import QtGui, QtCore


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 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)
        # self.qmenu.addMenu(base_qmenu)

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



    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,
                str(base_menu.title()),
                str(sub_menu_name)
            )
            action.setCheckable(True)
            action.setChecked(True)
            action.toggled.connect(slot)
            base_menu.addAction(action)

    def _callActionItem(self, title, menu):
        pass


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


1 个答案:

答案 0 :(得分:1)

我通常使用PySide。 我试图使用PySide解决这个问题。

因此,请查看此代码并执行。

import functools
import sys
from PyQt4 import QtGui, QtCore


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)
        # self.qmenu.addMenu(base_qmenu)

        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.unsetCheck_action)


        self.qmenu.addAction(test_action)

    def unsetCheck_action(self,checked):

        sender_obj = self.sender()
        if isinstance(sender_obj,QtGui.QAction): 


            sender_obj.setChecked(checked)




    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,
                str(base_menu.title()),
                str(sub_menu_name)
            )
            action.setCheckable(True)
            action.setChecked(True)
            action.toggled.connect(slot)
            base_menu.addAction(action)

    def _callActionItem(self, title, menu):
        pass


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

变化点。

1.CustomMenu具有MousePressEvent。

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

如果单击菜单上的操作,则会得到该操作。 然后您致电action.trigger() 并且您可以连接action.triggered Signal。 是的,“触发”是在“触发”之后。

2. 连接触发器。

self.connect(test_action,QtCore.SIGNAL("triggered(bool)"),self.unsetCheck_action)
def unsetCheck_action(self,checked):

        sender_obj = self.sender()
        if isinstance(sender_obj,QtGui.QAction): 


            sender_obj.setChecked(checked)

如您所见,如果触发了测试动作,则会触发触发信号。 插槽是unsetCheck_action方法。

要更改动作技巧,您只能操纵似乎是触发器的东西,而无需在True和False之间切换。

在PySide中消失

在PyQt中,最好通过test_action.triggered[bool].connect()连接 但是PySide我做不到。

我的机器上没有PyQt4。如果您有任何问题,请随时向我询问更多信息。