Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/android/205.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 如果QMenu中的QWidgetAction在_Python_Pyqt4_Qmenu_Qcheckbox_Qwidgetaction - Fatal编程技术网

Python 如果QMenu中的QWidgetAction在

Python 如果QMenu中的QWidgetAction在,python,pyqt4,qmenu,qcheckbox,qwidgetaction,Python,Pyqt4,Qmenu,Qcheckbox,Qwidgetaction,我试图在QMenu中实现三态复选框。 我的菜单层次结构类似于: menuA |-- a101 |-- a102 menuB |-- b101 其中第一层(menuA、menuB)为三态复选框,而其子项为正常复选框,使用QAction实现 因此,通过使用QWidgetAction和QCheckBox,我似乎能够让三态在第一层工作 但是,当我尝试使用将子项包含到第一层项中的setMenu时,即使选项能够相应地显示子项,选项也不再可检查 最初我只使用QAction小部件,但当

我试图在QMenu中实现三态复选框。 我的菜单层次结构类似于:

menuA
    |-- a101
    |-- a102
menuB
    |-- b101
其中第一层(menuA、menuB)为三态复选框,而其子项为正常复选框,使用QAction实现

因此,通过使用
QWidgetAction
QCheckBox
,我似乎能够让三态在第一层工作

但是,当我尝试使用将子项包含到第一层项中的
setMenu
时,即使选项能够相应地显示子项,选项也不再可检查

最初我只使用QAction小部件,但当我迭代子项时,第一层项始终显示为完整检查,如果可能的话,我想纠正它,因此我尝试使用三态

例如,如果选中了
a101
menuA
将设置为部分状态。如果同时选中了
a101
a102
,则
menuA
将设置为(完全)检查状态

class CustomCheckBox(QtGui.QCheckBox):
def uuu init uuuu(self,text=”“,parent=None):
超级(自定义复选框,自我)。\uuuuu初始化\uuuuuuuu(文本,父项=父项)
self.setText(文本)
self.setTristate(真)
类QSubAction(QtGui.QAction):
def uuu init uuuu(self,text=”“,parent=None):
超级(QSubAction,self)。\uuuu init\uuuu(文本,父级)
self.setCheckable(真)
self.toggled.connect(self.checkbox\u切换)
def复选框_切换(自身、值):
打印值
类QCustomMenu(QtGui.QMenu):
“”“自定义的QMenu。”“”
def uuu init uuuu(self,title,parent=None):
超级(QCustomMenu,self)。\uuuu初始化(title=str(title),parent=parent)
self.setup_菜单()
def鼠标压力事件(自身、事件):
action=self.activeAction()
如果不存在(action,QSubAction)且action不是None:
action.trigger()
返回
elif isinstance(动作、QSubAction):
action.toggle()
返回
返回QtGui.QMenu.mousePressEvent(self,event)
def设置菜单(自我):
self.setContextMenuPolicy(QtCore.Qt.DefaultContextMenu)
def contextMenuEvent(自身、事件):
没有右键点击=[卡扎菲行动]
如果有([isinstance(self.actionAt(event.pos()),instance),例如,在no_right_click中):
返回
pos=event.pos()
def添加操作(自我、操作):
超级(QCustomMenu,self).addAction(action)
类MainApp(QtGui.QWidget):
def uuu init uuu(self,parent=None):
超级(主应用程序,自我)。\uuuuu初始化\uuuuuuu(父级)
自检记录={
“种皮”:{
“菜单”:[“a101”、“a102”],
},
“testBC”:{
“菜单”:[“c101”、“c102”、“c103”],
“menuB”:[“b101”]
},
}
v_layout=QtGui.QVBoxLayout()
self.btn1=QtGui.QPushButton(“测试btn1”)
v_layout.addWidget(self.btn1)
self.setLayout(v_布局)
self.setup_connections()
def设置_连接(自):
self.btn1.clicked.connect(self.button1\u测试)
def按钮1_测试(自身):
self.qmen=qcustommen(title='',parent=self)
对于自测试目录项()中的pk、pv:
基本菜单=QCustomMenu(标题=主键,父菜单=自身)
基本复选框=自定义复选框(主键,基本菜单)
base\u action=QtGui.QWidgetAction(base\u复选框)
base_action.setMenu(base_qmenu)#这会导致选项不可检查
base\u action.setDefaultWidget(base\u复选框)
self.qmen.addAction(基本动作)
对于pv中的v:
动作=QSubAction(v,self)
基本菜单添加操作(操作)
self.qmenu.exec(QtGui.QCursor.pos())
如果名称=“\uuuuu main\uuuuuuuu”:
app=QtGui.QApplication(sys.argv)
w=MainApp()
w、 show()
sys.exit(app.exec_())

无法设置子菜单状态的原因是QMenu自动使用单击子菜单打开它,“使用”单击事件

要实现这一点,您必须确保用户单击的位置,如果它是QWidgetActions之一,则触发它,确保事件不会进一步传播

此外,三态逻辑被添加到子态,使用检查所有菜单操作以确定实际状态的
切换信号

请注意,contextMenuEvent(连同菜单策略设置)已被删除

最后,考虑使用一个不在菜单项中触发动作的复选框,因为它违背了菜单项的预期行为,这是违反直觉的。

class CustomCheckBox(QtGui.QCheckBox):
    def __init__(self, text="", parent=None):
        super(CustomCheckBox, self).__init__(text, parent=parent)

        self.setText(text)
        self.setTristate(True)

    def mousePressEvent(self, event):
        # only react to left click buttons and toggle, do not cycle
        # through the three states (which wouldn't make much sense)
        if event.button() == QtCore.Qt.LeftButton:
            self.toggle()

    def toggle(self):
        super(CustomCheckBox, self).toggle()
        newState = self.isChecked()
        for action in self.actions():
            # block the signal to avoid recursion
            oldState = action.isChecked()
            action.blockSignals(True)
            action.setChecked(newState)
            action.blockSignals(False)
            if oldState != newState:
                # if you *really* need to trigger the action, do it
                # only if the action wasn't already checked
                action.triggered.emit(newState)


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


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

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

    def mousePressEvent(self,event):
        actionAt = self.actionAt(event.pos())
        if isinstance(actionAt, QtGui.QWidgetAction):
            # the first mousePressEvent is sent from the parent menu, so the
            # QWidgetAction found is one of the sub menu actions
            actionAt.defaultWidget().toggle()
            return
        action = self.activeAction()
        if not isinstance(action,QSubAction) and action is not None:
            action.trigger()
            return
        elif isinstance(action,QSubAction):
            action.toggle()
            return
        QtGui.QMenu.mousePressEvent(self,event)

    def addAction(self, action):
        super(QCustomMenu, self).addAction(action)
        if isinstance(self.menuAction(), QtGui.QWidgetAction):
            # since this is a QWidgetAction menu, add the action
            # to the widget and connect the action toggled signal
            action.toggled.connect(self.checkChildrenState)
            self.menuAction().defaultWidget().addAction(action)

    def checkChildrenState(self):
        actionStates = [a.isChecked() for a in self.actions()]
        if all(actionStates):
            state = QtCore.Qt.Checked
        elif any(actionStates):
            state = QtCore.Qt.PartiallyChecked
        else:
            state = QtCore.Qt.Unchecked
        self.menuAction().defaultWidget().setCheckState(state)

您好@musciamante,谢谢您的回复。我注意到基本菜单缺少“右箭头”,这可能是因为使用了QWidgetAction吗?是的,是的。我假设QMenu决定只在找到注册到菜单的QAction时绘制箭头,这意味着它实际上绘制了QAction内容(因此它的特性是:图标、复选框/收音机和子菜单箭头),而如果有QWidgetAction,它只绘制周围的帧,剩下的部分由defaultWidget()完成。如果您想绘制箭头,恐怕您需要自己绘制,可能需要添加箭头字符或增加contentMargin()的右组件,并在paintEvent中绘制箭头。