【问题标题】:QMenu does not execute methods properlyQMenu 无法正确执行方法
【发布时间】:2020-02-27 17:10:11
【问题描述】:

我正在使用执行某些方法的自定义 QMenu。该菜单有三个选项:删除行选项、切换变量选项和调试选项,用于打印切换变量的值。代码未正确执行。有时调试按钮不起作用,它突然被执行了很多次。切换选项需要单击两次才能工作,我不知道为什么。这是我的 MRE:

# -*- coding: utf-8 -*-

from PyQt5.QtCore import Qt, QRect, pyqtSlot
from PyQt5.QtGui import QCursor
from PyQt5.QtWidgets import QWidget, QPushButton, QHBoxLayout, QMainWindow, QLabel, QMenu, \
    QApplication, QVBoxLayout, QListWidgetItem, QListWidget, QAction


class Punto(QWidget):
    def __init__(self, parent, internal_id, name):
        QWidget.__init__(self)

        # Toggle variable
        self.render = True

        self.customContextMenuRequested.connect(self.context_menu)
        self.setContextMenuPolicy(Qt.CustomContextMenu)
        self.menu = QMenu()
        self.borrar = QAction("Delete")
        self.ver = QAction("Toggle")
        self.debug = QAction("Debug")
        self.ver.setCheckable(True)
        self.ver.setChecked(True)

        self.parent = parent
        self.id = internal_id

        label = QLabel(name)
        hbox = QHBoxLayout()
        hbox.addWidget(label)
        hbox.addStretch(1)
        self.setLayout(hbox)

    def context_menu(self):
        self.menu.addAction(self.borrar)
        self.borrar.triggered.connect(self.delete)

        self.menu.addAction(self.ver)
        self.ver.triggered.connect(self.change)

        self.menu.addAction(self.debug)
        self.debug.triggered.connect(self.debugg)

        self.menu.exec(QCursor.pos())

    @pyqtSlot()
    def debugg(self):
        print(f"Render: {self.render}")

    @pyqtSlot()
    def change(self):
        if self.ver.isChecked():
            self.ver.setChecked(False)
            self.render = False
        else:
            self.ver.setChecked(True)
            self.render = True

    @property
    def itemid(self):
        return self.id

    @pyqtSlot()
    def delete(self):
        self.parent.delete_point(self.id)


class Ventana(QMainWindow):
    def __init__(self):
        QMainWindow.__init__(self)
        self.setFixedSize(200, 200)

        widget_central = QWidget(self)

        boton_punto = QPushButton(widget_central)
        boton_punto.setGeometry(QRect(0, 0, 200, 20))
        boton_punto.clicked.connect(self.crear_punto)

        boton_punto.setText("Create")

        widget_punto = QWidget(widget_central)
        widget_punto.setGeometry(QRect(0, 20, 200, 200))
        vertical_punto = QVBoxLayout(widget_punto)
        vertical_punto.setContentsMargins(0, 0, 0, 0)
        self.lista_puntos = QListWidget(widget_punto)

        vertical_punto.addWidget(self.lista_puntos)

        self.id_punto = 0
        self.setCentralWidget(widget_central)

    def crear_punto(self):
        # Add placeholder item to List
        item = QListWidgetItem()
        self.lista_puntos.addItem(item)
        # Create Custom Widget
        punto = Punto(self, self.id_punto, "A")
        self.id_punto += 1
        item.setSizeHint(punto.minimumSizeHint())
        # Set the punto widget to be displayed within the placeholder item
        self.lista_puntos.setItemWidget(item, punto)

    def delete_point(self, idd):
        for indx in range(self.lista_puntos.count()):
            item = self.lista_puntos.item(indx)
            widget = self.lista_puntos.itemWidget(item)
            if widget.id == idd:
                self.lista_puntos.takeItem(self.lista_puntos.row(item))
                break


if __name__ == "__main__":
    MainEvent = QApplication([])
    main_app = Ventana()
    main_app.show()
    MainEvent.exec()

【问题讨论】:

  • 查看选项是什么?
  • @eyllanesc 切换一号,我的错
  • 它适用于我的设置 python3.6,Centos 7,必须在复选框区域按下切换按钮才能切换
  • @PepeElMago33 你的错误是正确的,如果在早期版本中它不能重现它可能是由于一个错误。没有必要使用旧版本,试试我的解决方案。我已经在 Linux 上使用 Qt 5.13.1 对其进行了测试。
  • @chatzich 在python3中 exec_() 和 exec() 都是有效的。

标签: python python-3.x pyqt pyqt5 qmenu


【解决方案1】:

您有 2 个错误:

  • 默认情况下,QAction 已经进行了状态更改,因此您没有必要实现它,但您正在执行它,也就是说,默认情况下 QAction 从开启变为关闭(反之亦然),但是您通过代码将其从关闭(或反之亦然)更改为在 ms 中完成时不会观察到更改。因此,不要连接触发信号,而是使用切换信号并更改渲染。

  • 当您将信号连接到同一个插槽“n”次时,插槽被调用“n”次,并且在您的情况下,每次调用 context_menu 方法时都连接它,至少有 2 个解决方案: 只建立一次连接或使用 Qt::UniqueConnection 的连接类型,在我的解决方案中我将使用第一个。

综合以上,解决办法是:

class Punto(QWidget):
    def __init__(self, parent, internal_id, name):
        QWidget.__init__(self)

        # Toggle variable
        self.render = True

        self.customContextMenuRequested.connect(self.context_menu)
        self.setContextMenuPolicy(Qt.CustomContextMenu)
        self.menu = QMenu()
        self.borrar = QAction("Delete")
        self.ver = QAction("Toggle")
        self.debug = QAction("Debug")
        self.ver.setCheckable(True)
        self.ver.setChecked(True)

        self.parent = parent
        self.id = internal_id

        label = QLabel(name)
        hbox = QHBoxLayout(self)
        hbox.addWidget(label)
        hbox.addStretch(1)

        self.borrar.triggered.connect(self.delete)
        self.ver.toggled.connect(self.change)
        self.debug.triggered.connect(self.debugg)
        self.menu.addAction(self.borrar)
        self.menu.addAction(self.ver)
        self.menu.addAction(self.debug)

    def context_menu(self):
        self.menu.exec(QCursor.pos())

    @pyqtSlot()
    def debugg(self):
        print(f"Render: {self.render}")

    @pyqtSlot(bool)
    def change(self, state):
        self.render = self.ver.isChecked()

    @property
    def itemid(self):
        return self.id

    @pyqtSlot()
    def delete(self):
        self.parent.delete_point(self.id)

【讨论】:

    猜你喜欢
    • 2013-08-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-09-20
    • 2012-11-09
    相关资源
    最近更新 更多