In PyQt5, I am developing a sensors based GUI where i draw a toggle power off/on button in which i want to add a functionality where i toggle the power button and my desktop gui should be closed on that toggle. like we do in close [X] button of the gui.
here is the toggle.py code and call i on my main.py code
main.py
class MainWindow(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 code:
import pylab as p
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
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)
here in if condition i call mousePressEvent but its not working
Since the requirement is to close the window only when the check box is unchecked again, the solution is to connect to a function that will only close in that case. Note that you should not use the stateChanged
signal for dual state check boxes, as it returns a Qt.CheckState
enum, which has 3 states. Use the toggled
signal instead.
self.toggled.connect(self.checkForClose)
def checkForClose(self, state):
if not state:
self.close()
An important note about your attempt.
First of all, a paint function should never try to do something that is not directly related to drawing. This is important as those functions are called very often, potentially dozens of times each second, and in some cases even every time the mouse is moved above the widget.
Most importantly, your overwritten method just connects the clicked
signal, which is wrong for two reasons:
clicked
signal), you're preventing all of that - and the signal will never be emitted because it never gets checked/unchecked;Another important aspect to remember is that PyQt uses reference caching for functions; after the first time a virtual function is called with the default implementation, overwriting the instance attribute will have no effect.
Supposing you wanted to do the opposite (connect the signal when the state is True
), it wouldn't have worked because at that time the default mousePressEvent
handler would have been already called, and the overwriting would have had no effect at all.