Reputation: 1377
I simply want some elements inside a QDialog to be blinking (altering background color).
Now preferably I'd like to be able to use something that already exists and encapsulates the blinking state, i.e. blinking with css3 or maybe it is possible with QPropertyAnimation
?
Since I didn't find any nice info on that option I tried the less optimal solution:
excerpt from the Dialogs __init__
:
self.timer = QTimer()
self.timer.timeout.connect(self.update_blinking)
self.timer.start(250)
self.last_blinked = None
and
def update_blinking(self):
self.frame.setStyleSheet(
self.STYLE_BLINK_ON if self.blink else self.STYLE_BLINK_OFF)
self.blink = not self.blink
where STYLE_BLINK_ON
and STYLE_BLINK_OFF
are some css specifying the background colors.
That works but
Explanation for 2.: Assume the widget that should be blinking is a frame.
When a button inside that frame is clicked, the clicked
signal isn't emitted if a style-update of the frame occurs before the mouse-button is released.
A completely different solution that encapsulates things and doesn't require me to manually start a timer would of course be preferred. But I would be grateful if someone at least came up with a solution which solves point 2.
Upvotes: 3
Views: 7348
Reputation: 2160
The one way is to use QPropertyAnimation
. QPropertyAnimation
interpolates over Qt properties - this fact causes difficulties:
1) Change appearance via style sheet -- animation cannot work with strings, because they're not interpolable.
2) Manipulate background directly -- background color is stored deep inside QWidget.palette
, it's not a QProperty
. The possible solution is to transform background color into a widget's property:
class AnimatedWidget(QtGui.QWidget):
def __init__(self):
QtGui.QWidget.__init__(self)
color1 = QtGui.QColor(255, 0, 0)
color2 = QtGui.QColor(0, 255, 0)
self.color_anim = QtCore.QPropertyAnimation(self, 'backColor')
self.color_anim.setStartValue(color1)
self.color_anim.setKeyValueAt(0.5, color2)
self.color_anim.setEndValue(color1)
self.color_anim.setDuration(1000)
self.color_anim.setLoopCount(-1)
self.color_anim.start()
def getBackColor(self):
return self.palette().color(QtGui.QPalette.Background)
def setBackColor(self, color):
pal = self.palette()
pal.setColor(QtGui.QPalette.Background, color)
self.setPalette(pal)
backColor = QtCore.pyqtProperty(QtGui.QColor, getBackColor, setBackColor)
The other approach is dealing with QStateMachine
s. They're able to manipulate any properties, not only interpolable ones:
class StateWidget(QtGui.QWidget):
def __init__(self):
QtGui.QWidget.__init__(self)
style1 = "background-color: yellow"
style2 = "background-color: black"
# animation doesn't work for strings but provides an appropriate delay
animation = QtCore.QPropertyAnimation(self, 'styleSheet')
animation.setDuration(150)
state1 = QtCore.QState()
state2 = QtCore.QState()
state1.assignProperty(self, 'styleSheet', style1)
state2.assignProperty(self, 'styleSheet', style2)
# change a state after an animation has played
# v
state1.addTransition(state1.propertiesAssigned, state2)
state2.addTransition(state2.propertiesAssigned, state1)
self.machine = QtCore.QStateMachine()
self.machine.addDefaultAnimation(animation)
self.machine.addState(state1)
self.machine.addState(state2)
self.machine.setInitialState(state1)
self.machine.start()
Upvotes: 7