I have an animated toggle widget that i put in a QTableWidget. Now i'm not able to get the signal of what toggle changed in QTable. In this example when i click the toggle its only working with 1 item name so i don't know still what item fired the signal!
This is what i've tried
from PySide6.QtCore import (
Qt,
QSize,
QPoint,
QPointF,
QRectF,
QEasingCurve,
QPropertyAnimation,
QSequentialAnimationGroup,
Slot,
Property,
)
from PySide6.QtWidgets import QCheckBox
from PySide6.QtGui import QColor, QBrush, QPaintEvent, QPen, QPainter
class AnimatedToggle(QCheckBox):
_transparent_pen = QPen(Qt.transparent)
_light_grey_pen = QPen(Qt.lightGray)
def __init__(
self,
parent=None,
bar_color=Qt.gray,
checked_color="#00B0FF",
handle_color=Qt.white,
pulse_unchecked_color="#44999999",
pulse_checked_color="#4400B0EE",
):
super().__init__(parent)
# Save our properties on the object via self, so we can access them later
# in the paintEvent.
self._bar_brush = QBrush(bar_color)
self._bar_checked_brush = QBrush(QColor(checked_color).lighter())
self._handle_brush = QBrush(handle_color)
self._handle_checked_brush = QBrush(QColor(checked_color))
self._pulse_unchecked_animation = QBrush(QColor(pulse_unchecked_color))
self._pulse_checked_animation = QBrush(QColor(pulse_checked_color))
# Setup the rest of the widget.
self.setContentsMargins(8, 0, 8, 0)
self._handle_position = 0
self._pulse_radius = 0
self.animation = QPropertyAnimation(self, b"handle_position", self)
self.animation.setEasingCurve(QEasingCurve.InOutCubic)
self.animation.setDuration(200) # time in ms
self.pulse_anim = QPropertyAnimation(self, b"pulse_radius", self)
self.pulse_anim.setDuration(0) # time in ms
self.pulse_anim.setStartValue(10)
self.pulse_anim.setEndValue(20)
self.animations_group = QSequentialAnimationGroup()
self.animations_group.addAnimation(self.animation)
self.animations_group.addAnimation(self.pulse_anim)
self.stateChanged.connect(self.setup_animation)
def sizeHint(self):
return QSize(58, 45)
def hitButton(self, pos: QPoint):
return self.contentsRect().contains(pos)
@Slot(int)
def setup_animation(self, value):
self.animations_group.stop()
if value:
self.animation.setEndValue(1)
else:
self.animation.setEndValue(0)
self.animations_group.start()
def paintEvent(self, e: QPaintEvent):
contRect = self.contentsRect()
handleRadius = round(0.24 * contRect.height())
p = QPainter(self)
p.setRenderHint(QPainter.Antialiasing)
p.setPen(self._transparent_pen)
barRect = QRectF(0, 0, contRect.width() - handleRadius, 0.40 * contRect.height())
barRect.moveCenter(contRect.center())
rounding = barRect.height() / 2
# the handle will move along this line
trailLength = contRect.width() - 2 * handleRadius
xPos = contRect.x() + handleRadius + trailLength * self._handle_position
if self.pulse_anim.state() == QPropertyAnimation.Running:
p.setBrush(self._pulse_checked_animation if self.isChecked() else self._pulse_unchecked_animation)
p.drawEllipse(QPointF(xPos, barRect.center().y()), self._pulse_radius, self._pulse_radius)
if self.isChecked():
p.setBrush(self._bar_checked_brush)
p.drawRoundedRect(barRect, rounding, rounding)
p.setBrush(self._handle_checked_brush)
else:
p.setBrush(self._bar_brush)
p.drawRoundedRect(barRect, rounding, rounding)
p.setPen(self._light_grey_pen)
p.setBrush(self._handle_brush)
p.drawEllipse(QPointF(xPos, barRect.center().y()), handleRadius, handleRadius)
p.end()
@Property(float)
def handle_position(self):
return self._handle_position
@handle_position.setter
def handle_position(self, pos):
"""change the property
we need to trigger QWidget.update() method, either by:
1- calling it here [ what we're doing ].
2- connecting the QPropertyAnimation.valueChanged() signal to it.
"""
self._handle_position = pos
self.update()
@Property(float)
def pulse_radius(self):
return self._pulse_radius
@pulse_radius.setter
def pulse_radius(self, pos):
self._pulse_radius = pos
self.update()
animated_toggle.py
from PySide6.QtWidgets import (
QApplication,
QMainWindow,
QTableWidgetItem,
QWidget,
QHBoxLayout,
QLabel,
QTableWidget,
QFrame,
QSizePolicy,
QLayout,
)
from PySide6 import QtCore, QtGui
from PySide6.QtUiTools import QUiLoader
import sys, os
from animated_toggle import AnimatedToggle
from qt_material import apply_stylesheet
os.chdir(os.path.dirname(__file__))
class Ui(QMainWindow):
def __init__(self):
super(Ui, self).__init__()
self.main = QUiLoader().load("main_window.ui", self)
apply_stylesheet(self.main, theme="my_theme.xml")
# Define objects
self.label = self.findChild(QLabel, "label")
self.label_2 = self.findChild(QLabel, "label_2")
self.label_3 = self.findChild(QLabel, "label_3")
self.tableWidget = self.findChild(QTableWidget, "tableWidget")
self.tableWidget_2 = self.findChild(QTableWidget, "tableWidget_2")
self.frame = self.findChild(QFrame, "frame")
self.frame_2 = self.findChild(QFrame, "frame_2")
# fixing styles
self.label.setStyleSheet("font-weight: bold")
self.label_2.setStyleSheet("font-weight: bold")
self.label_3.setStyleSheet("font-weight: bold")
self.tableWidget.setStyleSheet(
"QTableView#tableWidget { background-color: #152249;alternate-background-color: #1a2754;}"
)
self.tableWidget.horizontalHeader().setStyleSheet(
"QHeaderView::section { font-weight: bold; color: #ffb900; border-right: 0px; border-bottom: 0px; border-top:2px }"
)
self.tableWidget_2.setStyleSheet("QTableView#tableWidget_2 { background-color: #1d2c5d;}")
self.frame_2.setStyleSheet("QFrame#frame_2 { border: 2px solid #020b1a;} ")
self.frame.setStyleSheet("QFrame#frame { border: 2px solid #020b1a;} ")
self.fill_location_table()
def fill_location_table(self):
self.toggles = []
for i in range(self.tableWidget_2.rowCount()):
for j in range(self.tableWidget_2.columnCount()):
name = f"{i}_{j}"
self.container = QWidget()
self.mainToggle = AnimatedToggle()
self.toggles.append(self.mainToggle)
self.mainToggle.setFixedSize(QtCore.QSize(51, 38))
# self.mainToggle.stateChanged.connect(lambda: self.uncheck(name))
layout = QHBoxLayout()
layout.setContentsMargins(0, 0, 0, 0)
layout.setSizeConstraint(QLayout.SetMinimumSize)
self.container.setStyleSheet("QWidget { background-color: #1d2c5d;}")
self.container.setLayout(layout)
self.mainToggle.stateChanged.connect(lambda: self.uncheck(name))
self.container.layout().addWidget(QLabel(name))
self.container.layout().addWidget(self.mainToggle)
self.tableWidget_2.setCellWidget(i, j, self.container)
def uncheck(self, item):
print(item)
if __name__ == "__main__":
QtCore.QCoreApplication.setAttribute(QtCore.Qt.AA_ShareOpenGLContexts)
app = QApplication(sys.argv)
window = Ui()
window.main.show()
app.exec()
main.py
thanks to all for the help!