Recently, I have been struggling with understanding of pyqtProperty usage. In following snippet I try to create a custom button which would change it's text and appearance after clicking on it. I wanted to separate logic and appearance, so I've created custom property 'state', which is used in the stylesheet.
The result looks kind of strange to me. Program throws 'CustomButton' object has no attribute '_state'
exception, but runs anyway. Button's text is changing after clicking on it, but color stays the same.
#!/usr/bin/python
# -*- coding: utf-8 -*-
import sys
from PyQt4 import QtGui, QtCore
STYLE = '''
CustomButton {
margin: 50px;
padding: 10px;
}
CustomButton[state='true'] {
background: yellowgreen;
}
CustomButton[state='false'] {
background: orangered;
}
'''
class CustomButton(QtGui.QPushButton):
def __init__(self):
super(CustomButton, self).__init__()
self.setText('ON')
self.setStyleSheet(STYLE)
self._state = True
def g_state(self):
return self._state
def s_state(self, value):
self._state = value
state = QtCore.pyqtProperty(bool, fget=g_state, fset=s_state)
def mousePressEvent(self, event):
print 'clicked'
if self.state == True:
self.state = False
self.setText('OFF')
else:
self.state = True
self.setText('ON')
if __name__ == '__main__':
app = QtGui.QApplication(sys.argv)
b = CustomButton()
b.show()
sys.exit(app.exec_())
There are a couple of issues here.
Firstly, the re-implemented mousePressEvent
should call the base-class implementation in order to retain the normal behaviour.
Secondly, changes to properties do not automatically trigger style changes, so you need to explicitly do that in your code.
Also, its worth noting that pyqtProperty
can be used as a decorator, which might improve the readability of the code a little.
So, with these changes, the code might look something like this:
...
@QtCore.pyqtProperty(bool)
def state(self):
return self._state
@state.setter
def state(self, value):
self._state = value
def mousePressEvent(self, event):
print 'clicked'
if self.state:
self.state = False
self.setText('OFF')
else:
self.state = True
self.setText('ON')
self.style().unpolish(self)
self.style().polish(self)
self.update()
super(CustomButton, self).mousePressEvent(event)