如何在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
信号,这是错误的,原因有两个:
- 除了连接信号外,您的覆盖不会做任何其他事情,并且由于 QCheckBox 需要处理鼠标事件才能正确更改其状态(并最终发出
clicked
信号),您防止所有这些 - 并且信号永远不会发出,因为它永远不会 checked/unchecked;
- 每按任意鼠标键,信号就会接通;由于上述原因,它根本不会有任何结果,但这在概念上仍然是错误的,因为连接函数总是会被调用多次,因为它已连接到信号:你连接了两次?该函数将被调用两次;假设将发出信号(使用键盘仍然可能发生),相关函数将在用户尝试单击它时被调用多次。
要记住的另一个重要方面是 PyQt 对函数使用引用缓存;第一次使用默认实现调用虚函数后,覆盖实例属性将无效。
假设你想做相反的事情(在状态为 True
时连接信号),它不会起作用,因为那时默认的 mousePressEvent
处理程序已经被调用, 并且覆盖根本没有效果。
在 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
信号,这是错误的,原因有两个:
- 除了连接信号外,您的覆盖不会做任何其他事情,并且由于 QCheckBox 需要处理鼠标事件才能正确更改其状态(并最终发出
clicked
信号),您防止所有这些 - 并且信号永远不会发出,因为它永远不会 checked/unchecked; - 每按任意鼠标键,信号就会接通;由于上述原因,它根本不会有任何结果,但这在概念上仍然是错误的,因为连接函数总是会被调用多次,因为它已连接到信号:你连接了两次?该函数将被调用两次;假设将发出信号(使用键盘仍然可能发生),相关函数将在用户尝试单击它时被调用多次。
要记住的另一个重要方面是 PyQt 对函数使用引用缓存;第一次使用默认实现调用虚函数后,覆盖实例属性将无效。
假设你想做相反的事情(在状态为 True
时连接信号),它不会起作用,因为那时默认的 mousePressEvent
处理程序已经被调用, 并且覆盖根本没有效果。