如何在pyqt中的paintEvent的if & else下调用mousePressEvent?

how to call mousePressEvent under if & else of paintEvent in pyqt?

在 PyQt5 中,我正在开发一个基于传感器的 GUI,我在其中绘制了一个切换电源 off/on 按钮,我想在其中添加一个功能,在该功能中我切换电源按钮并且我的桌面 gui 应该在该按钮上关闭切换。就像我们在 gui 的关闭 [X] 按钮中所做的那样。

这是 toggle.py 代码,用我的 main.py 代码调用 i

main.py


class 主窗口(QMainWindow):

def __init__(self):
    super().__init__()
    # main dialog box
    self.turning_Icon = None
    self.setWindowTitle("Hatchery System")
    self.setStyleSheet("background-color: #2c313c;")
    self.setFixedWidth(1400)
    self.setFixedHeight(950)
    self.setWindowFlags(Qt.FramelessWindowHint)

    # Create Container and Layout
    self.container = QFrame(self)
    self.container.move(100, 50)
    self.container.resize(100, 50)
    self.container.setStyleSheet("background-color: #2c313c;")
    self.container.layout = QVBoxLayout()
    
    # toggle_power_button
    self.toggle = PyToggle()
    self.toggle.setStyleSheet("background-color: white")
    self.toggle.move(50, 50)
    self.container.layout.addWidget(self.toggle, Qt.AlignCenter, Qt.AlignCenter)
    self.container.setLayout(self.container.layout)

toggle.py代码:


将 pylab 导入为 p
来自 PyQt5.QtCore 导入 *
从 PyQt5.QtGui 导入 *
来自 PyQt5.QtWidgets 导入 *

class PyToggle(QCheckBox):

def __init__(
        self,
        width=60,
        # height=50,
        bg_color="#777",
        circle_color="#fff",
        active_color="#00BCff"
        # active_color="red"

):
    QCheckBox.__init__(self)

    self.setFixedSize(width, 28)
    # self.setFixedSize(height, 40)
    self.setCursor(Qt.PointingHandCursor)

    # colors
    self._bg_color = bg_color
    self._circle_color = circle_color
    self._active_color = active_color

    # connect state changed
    self.stateChanged.connect(self.debug)

def debug(self):
    print(f"status: {self.isChecked()}")

def hitButton(self, pos: QPoint):
    return self.contentsRect().contains(pos)

def paintEvent(self, e):
    # SET painter
    p = QPainter(self)
    p.setRenderHint(QPainter.Antialiasing)
    p.setPen(Qt.NoPen)

    rect = QRect(0, 0, self.width(), self.height())

    p.setBrush(QColor(self._bg_color))
    p.drawRoundedRect(0, 0, rect.width(), self.height(), self.height() / 2, self.height() / 2)
    p.end()

def paintEvent(self, e):
    # SET painter
    p = QPainter(self)
    p.setRenderHint(QPainter.Antialiasing)

    # SET as No PEN
    p.setPen(Qt.NoPen)

    # draw rect
    rect = QRect(0, 0, self.width(), self.height())

    if not self.isChecked():
        # draw BG
        p.setBrush(QColor(self._bg_color))
        p.drawRoundedRect(0, 0, rect.width(), self.height(), self.height()/2, self.height()/2)

        p.setBrush(QColor(self._circle_color))
        p.drawEllipse(3, 3, 22, 22)
        p.mousePressEvent = self.clickLine
    else:
        p.setBrush(QColor(self._active_color))
        p.drawRoundedRect(0, 0, rect.width(), self.height(), self.height() / 2, self.height() / 2)

        p.setBrush(QColor(self._circle_color))
        p.drawEllipse(self.width() - 26, 3, 22, 22)

def clickLine(self, mouseEvent):
    p.clicked.connect(self.close)

这里在 if 条件下我调用了 mousePressEvent 但它不起作用

输出:


取消选中它关闭我的桌面 gui 应该关闭。

由于要求仅当再次取消选中复选框时才关闭 window,因此解决方案是连接到仅在这种情况下关闭的功能。请注意,您不应将 stateChanged 信号用于双状态复选框,因为它 returns 一个 Qt.CheckState 枚举,它有 3 个状态。请改用 toggled 信号。

        self.toggled.connect(self.checkForClose)

    def checkForClose(self, state):
        if not state:
            self.close()

关于您尝试的重要说明。

首先,绘画函数不应该尝试做一些与绘画没有直接关系的事情。这一点很重要,因为这些函数被调用的频率很高,每秒可能调用几十次,在某些情况下甚至每次鼠标移到小部件上方时都会被调用。

最重要的是,您的覆盖方法只是连接了 clicked 信号,这是错误的,原因有两个:

  1. 除了连接信号外,您的覆盖不会做任何其他事情,并且由于 QCheckBox 需要处理鼠标事件才能正确更改其状态(并最终发出 clicked 信号),您防止所有这些 - 并且信号永远不会发出,因为它永远不会 checked/unchecked;
  2. 每按任意鼠标键,信号就会接通;由于上述原因,它根本不会有任何结果,但这在概念上仍然是错误的,因为连接函数总是会被调用多次,因为它已连接到信号:你连接了两次?该函数将被调用两次;假设将发出信号(使用键盘仍然可能发生),相关函数将在用户尝试单击它时被调用多次。

要记住的另一个重要方面是 PyQt 对函数使用引用缓存;第一次使用默认实现调用虚函数后,覆盖实例属性将无效。

假设你想做相反的事情(在状态为 True 时连接信号),它不会起作用,因为那时默认的 mousePressEvent 处理程序已经被调用, 并且覆盖根本没有效果。