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)
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top