PyQt 中的切换按钮
Toggle button in PyQt
我在 PyQt4 中实现了以下切换按钮,但我不明白为什么它在 "OFF" 状态下没有按预期运行。我无法理解问题所在。任何帮助都将是宝贵的,我们将不胜感激。
在此,您可以找到我附上的代码。
from PyQt4.QtCore import QObject
from PyQt4.QtGui import QPen
from PyQt4.QtGui import QBrush
from PyQt4.QtGui import QPalette
from PyQt4.QtGui import QAbstractButton
from PyQt4.QtGui import QPainter
from PyQt4.QtGui import QApplication
from PyQt4.QtCore import QRectF
from PyQt4.QtGui import QLinearGradient, QGradient
from PyQt4.QtCore import QPropertyAnimation
from PyQt4.QtCore import QEasingCurve
from PyQt4.QtCore import Qt, QSize
from PyQt4.QtCore import pyqtProperty, pyqtSlot
class QSlideSwitchPrivate(QObject):
def __init__(self, q):
QObject.__init__(self)
self._position = 0
self._sliderShape = QRectF()
self._gradient = QLinearGradient()
self._gradient.setSpread(QGradient.PadSpread)
self._qPointer = q
self.animation = QPropertyAnimation(self)
self.animation.setTargetObject(self)
self.animation.setPropertyName("position")
self.animation.setStartValue(0)
self.animation.setEndValue(1)
self.animation.setDuration(300)
self.animation.setEasingCurve(QEasingCurve.InOutExpo)
def __del__(self):
del self.animation
@pyqtProperty(float)
def position(self):
return self._position
@position.setter
def position(self, value):
self._position = value
self._qPointer.repaint()
def drawSlider(self, painter):
margin = 3
r = self._qPointer.rect().adjusted(0,0,-1,-1)
dx = (r.width() - self._sliderShape.width()) * self._position
sliderRect = self._sliderShape.translated(dx, 0)
painter.setPen(Qt.NoPen)
# basic settings
shadow = self._qPointer.palette().color(QPalette.Dark)
light = self._qPointer.palette().color(QPalette.Light)
button = self._qPointer.palette().color(QPalette.Button)
# draw background
# draw outer background
self._gradient.setColorAt(0, shadow.darker(130))
self._gradient.setColorAt(1, light.darker(130))
self._gradient.setStart(0, r.height())
self._gradient.setFinalStop(0, 0)
painter.setBrush(self._gradient)
painter.drawRoundedRect(r, 15, 15)
# draw background
# draw inner background
self._gradient.setColorAt(0, shadow.darker(140))
self._gradient.setColorAt(1, light.darker(160))
self._gradient.setStart(0, 0)
self._gradient.setFinalStop(0, r.height())
painter.setBrush(self._gradient)
painter.drawRoundedRect(r.adjusted(margin, margin, -margin, -margin), 15, 15)
# draw slider
self._gradient.setColorAt(0, button.darker(130))
self._gradient.setColorAt(1, button)
# draw outer slider
self._gradient.setStart(0, r.height())
self._gradient.setFinalStop(0, 0)
painter.setBrush(self._gradient)
painter.drawRoundedRect(sliderRect.adjusted(margin, margin, -margin, -margin), 10, 15)
# draw inner slider
self._gradient.setStart(0, 0)
self._gradient.setFinalStop(0, r.height())
painter.setBrush(self._gradient)
painter.drawRoundedRect(sliderRect.adjusted(2.5 * margin, 2.5 * margin, -2.5 * margin, - 2.5 * margin), 5, 15)
# draw text
if self.animation.state() == QPropertyAnimation.Running:
return #don't draw any text while animation is running
font = self._qPointer.font()
self._gradient.setColorAt(0, light)
self._gradient.setColorAt(1, shadow)
self._gradient.setStart(0, r.height() / 2.0 + font.pointSizeF())
self._gradient.setFinalStop(0, r.height() / 2.0 - font.pointSizeF())
painter.setFont(font)
painter.setPen(QPen(QBrush(self._gradient), 0))
if self._qPointer.isChecked():
painter.drawText(0, 0, r.width() / 2, r.height()-1, Qt.AlignCenter, "ON")
else:
painter.drawText( r.width() / 2, 0, r.width() / 2, r.height() - 1, Qt.AlignCenter, "OFF")
def updateSliderRect(self, size):
self._sliderShape.setWidth(size.width() / 2.0)
self._sliderShape.setHeight(size.height() - 1.0)
@pyqtSlot(bool, name='animate')
def animate(self, checked):
self.animation.setDirection = QPropertyAnimation.Forward if checked else QPropertyAnimation.Backward
print(self.animation.setDirection)
self.animation.start()
class QSlideSwitch(QAbstractButton):
def __init__(self, parent = None):
super(QAbstractButton, self).__init__(parent)
self.d_ptr = QSlideSwitchPrivate( self )
self.clicked.connect( self.d_ptr.animate )
self.d_ptr.animation.finished.connect( self.update )
def __del__(self):
del self.d_ptr
def sizeHint(self):
return QSize(48, 28)
def hitButton(self, point):
return self.rect().contains(point)
def paintEvent(self, event):
painter = QPainter(self)
painter.setRenderHint(QPainter.Antialiasing)
self.d_ptr.drawSlider(painter)
def resizeEvent(self, event):
self.d_ptr.updateSliderRect(event.size())
self.repaint()
if __name__ == '__main__':
import sys
app = QApplication(sys.argv)
switcher = QSlideSwitch()
switcher.setCheckable(True)
switcher.show()
sys.exit(app.exec_())
问题是您没有更改 QPropertyAnimation
的地址。您不能使用 {your QPropertyAnimation}.setDirection = {some value}
,而是 {your QPropertyAnimation}.setDirection({some value})
。您必须更改为
@pyqtSlot(bool, name='animate')
def animate(self, checked):
self.animation.setDirection(QPropertyAnimation.Forward if checked else QPropertyAnimation.Backward)
self.animation.start()
PyQt5 中的实现
from PyQt5.QtCore import Qt, pyqtSlot, QObject, QPropertyAnimation, QEasingCurve, QRectF, pyqtProperty, QSize
from PyQt5.QtGui import QLinearGradient, QGradient, QPalette, QPainter, QBrush, QPen
from PyQt5.QtWidgets import QApplication, QAbstractButton
class QSlideSwitchPrivate(QObject):
def __init__(self, q):
QObject.__init__(self)
self._position = 0
self._sliderShape = QRectF()
self._gradient = QLinearGradient()
self._gradient.setSpread(QGradient.PadSpread)
self._qPointer = q
self.animation = QPropertyAnimation(self)
self.animation.setTargetObject(self)
self.animation.setPropertyName(b"position")
self.animation.setStartValue(0)
self.animation.setEndValue(1)
self.animation.setDuration(300)
self.animation.setEasingCurve(QEasingCurve.InOutExpo)
def __del__(self):
del self.animation
@pyqtProperty(float)
def position(self):
return self._position
@position.setter
def position(self, value):
self._position = value
self._qPointer.repaint()
def drawSlider(self, painter):
margin = 3
r = self._qPointer.rect().adjusted(0, 0, -1, -1)
dx = (r.width() - self._sliderShape.width()) * self._position
sliderRect = self._sliderShape.translated(dx, 0)
painter.setPen(Qt.NoPen)
# basic settings
shadow = self._qPointer.palette().color(QPalette.Dark)
light = self._qPointer.palette().color(QPalette.Light)
button = self._qPointer.palette().color(QPalette.Button)
# draw background
# draw outer background
self._gradient.setColorAt(0, shadow.darker(130))
self._gradient.setColorAt(1, light.darker(130))
self._gradient.setStart(0, r.height())
self._gradient.setFinalStop(0, 0)
painter.setBrush(self._gradient)
painter.drawRoundedRect(r, 15, 15)
# draw background
# draw inner background
self._gradient.setColorAt(0, shadow.darker(140))
self._gradient.setColorAt(1, light.darker(160))
self._gradient.setStart(0, 0)
self._gradient.setFinalStop(0, r.height())
painter.setBrush(self._gradient)
painter.drawRoundedRect(r.adjusted(margin, margin, -margin, -margin), 15, 15)
# draw slider
self._gradient.setColorAt(0, button.darker(130))
self._gradient.setColorAt(1, button)
# draw outer slider
self._gradient.setStart(0, r.height())
self._gradient.setFinalStop(0, 0)
painter.setBrush(self._gradient)
painter.drawRoundedRect(sliderRect.adjusted(margin, margin, -margin, -margin), 10, 15)
# draw inner slider
self._gradient.setStart(0, 0)
self._gradient.setFinalStop(0, r.height())
painter.setBrush(self._gradient)
painter.drawRoundedRect(sliderRect.adjusted(2.5 * margin, 2.5 * margin, -2.5 * margin, - 2.5 * margin), 5, 15)
# draw text
if self.animation.state() == QPropertyAnimation.Running:
return # don't draw any text while animation is running
font = self._qPointer.font()
self._gradient.setColorAt(0, light)
self._gradient.setColorAt(1, shadow)
self._gradient.setStart(0, r.height() / 2.0 + font.pointSizeF())
self._gradient.setFinalStop(0, r.height() / 2.0 - font.pointSizeF())
painter.setFont(font)
painter.setPen(QPen(QBrush(self._gradient), 0))
if self._qPointer.isChecked():
painter.drawText(0, 0, int(r.width() / 2), r.height() - 1, Qt.AlignCenter, "ON")
else:
painter.drawText(int(r.width() / 2), 0, int(r.width() / 2), r.height() - 1, Qt.AlignCenter, "OFF")
def updateSliderRect(self, size):
self._sliderShape.setWidth(size.width() / 2.0)
self._sliderShape.setHeight(size.height() - 1.0)
@pyqtSlot(bool, name='animate')
def animate(self, checked):
self.animation.setDirection(QPropertyAnimation.Forward if checked else QPropertyAnimation.Backward)
self.animation.start()
class QSlideSwitch(QAbstractButton):
def __init__(self, parent=None):
super(QAbstractButton, self).__init__(parent)
self.d_ptr = QSlideSwitchPrivate(self)
self.clicked.connect(self.d_ptr.animate)
self.d_ptr.animation.finished.connect(self.update)
# def __del__(self):
# del self.d_ptr
def sizeHint(self):
return QSize(48, 28)
def hitButton(self, point):
return self.rect().contains(point)
def paintEvent(self, event):
painter = QPainter(self)
painter.setRenderHint(QPainter.Antialiasing)
self.d_ptr.drawSlider(painter)
def resizeEvent(self, event):
self.d_ptr.updateSliderRect(event.size())
self.repaint()
if __name__ == '__main__':
import sys
app = QApplication(sys.argv)
switcher = QSlideSwitch()
switcher.setCheckable(True)
switcher.show()
sys.exit(app.exec_())
我在 PyQt4 中实现了以下切换按钮,但我不明白为什么它在 "OFF" 状态下没有按预期运行。我无法理解问题所在。任何帮助都将是宝贵的,我们将不胜感激。
在此,您可以找到我附上的代码。
from PyQt4.QtCore import QObject
from PyQt4.QtGui import QPen
from PyQt4.QtGui import QBrush
from PyQt4.QtGui import QPalette
from PyQt4.QtGui import QAbstractButton
from PyQt4.QtGui import QPainter
from PyQt4.QtGui import QApplication
from PyQt4.QtCore import QRectF
from PyQt4.QtGui import QLinearGradient, QGradient
from PyQt4.QtCore import QPropertyAnimation
from PyQt4.QtCore import QEasingCurve
from PyQt4.QtCore import Qt, QSize
from PyQt4.QtCore import pyqtProperty, pyqtSlot
class QSlideSwitchPrivate(QObject):
def __init__(self, q):
QObject.__init__(self)
self._position = 0
self._sliderShape = QRectF()
self._gradient = QLinearGradient()
self._gradient.setSpread(QGradient.PadSpread)
self._qPointer = q
self.animation = QPropertyAnimation(self)
self.animation.setTargetObject(self)
self.animation.setPropertyName("position")
self.animation.setStartValue(0)
self.animation.setEndValue(1)
self.animation.setDuration(300)
self.animation.setEasingCurve(QEasingCurve.InOutExpo)
def __del__(self):
del self.animation
@pyqtProperty(float)
def position(self):
return self._position
@position.setter
def position(self, value):
self._position = value
self._qPointer.repaint()
def drawSlider(self, painter):
margin = 3
r = self._qPointer.rect().adjusted(0,0,-1,-1)
dx = (r.width() - self._sliderShape.width()) * self._position
sliderRect = self._sliderShape.translated(dx, 0)
painter.setPen(Qt.NoPen)
# basic settings
shadow = self._qPointer.palette().color(QPalette.Dark)
light = self._qPointer.palette().color(QPalette.Light)
button = self._qPointer.palette().color(QPalette.Button)
# draw background
# draw outer background
self._gradient.setColorAt(0, shadow.darker(130))
self._gradient.setColorAt(1, light.darker(130))
self._gradient.setStart(0, r.height())
self._gradient.setFinalStop(0, 0)
painter.setBrush(self._gradient)
painter.drawRoundedRect(r, 15, 15)
# draw background
# draw inner background
self._gradient.setColorAt(0, shadow.darker(140))
self._gradient.setColorAt(1, light.darker(160))
self._gradient.setStart(0, 0)
self._gradient.setFinalStop(0, r.height())
painter.setBrush(self._gradient)
painter.drawRoundedRect(r.adjusted(margin, margin, -margin, -margin), 15, 15)
# draw slider
self._gradient.setColorAt(0, button.darker(130))
self._gradient.setColorAt(1, button)
# draw outer slider
self._gradient.setStart(0, r.height())
self._gradient.setFinalStop(0, 0)
painter.setBrush(self._gradient)
painter.drawRoundedRect(sliderRect.adjusted(margin, margin, -margin, -margin), 10, 15)
# draw inner slider
self._gradient.setStart(0, 0)
self._gradient.setFinalStop(0, r.height())
painter.setBrush(self._gradient)
painter.drawRoundedRect(sliderRect.adjusted(2.5 * margin, 2.5 * margin, -2.5 * margin, - 2.5 * margin), 5, 15)
# draw text
if self.animation.state() == QPropertyAnimation.Running:
return #don't draw any text while animation is running
font = self._qPointer.font()
self._gradient.setColorAt(0, light)
self._gradient.setColorAt(1, shadow)
self._gradient.setStart(0, r.height() / 2.0 + font.pointSizeF())
self._gradient.setFinalStop(0, r.height() / 2.0 - font.pointSizeF())
painter.setFont(font)
painter.setPen(QPen(QBrush(self._gradient), 0))
if self._qPointer.isChecked():
painter.drawText(0, 0, r.width() / 2, r.height()-1, Qt.AlignCenter, "ON")
else:
painter.drawText( r.width() / 2, 0, r.width() / 2, r.height() - 1, Qt.AlignCenter, "OFF")
def updateSliderRect(self, size):
self._sliderShape.setWidth(size.width() / 2.0)
self._sliderShape.setHeight(size.height() - 1.0)
@pyqtSlot(bool, name='animate')
def animate(self, checked):
self.animation.setDirection = QPropertyAnimation.Forward if checked else QPropertyAnimation.Backward
print(self.animation.setDirection)
self.animation.start()
class QSlideSwitch(QAbstractButton):
def __init__(self, parent = None):
super(QAbstractButton, self).__init__(parent)
self.d_ptr = QSlideSwitchPrivate( self )
self.clicked.connect( self.d_ptr.animate )
self.d_ptr.animation.finished.connect( self.update )
def __del__(self):
del self.d_ptr
def sizeHint(self):
return QSize(48, 28)
def hitButton(self, point):
return self.rect().contains(point)
def paintEvent(self, event):
painter = QPainter(self)
painter.setRenderHint(QPainter.Antialiasing)
self.d_ptr.drawSlider(painter)
def resizeEvent(self, event):
self.d_ptr.updateSliderRect(event.size())
self.repaint()
if __name__ == '__main__':
import sys
app = QApplication(sys.argv)
switcher = QSlideSwitch()
switcher.setCheckable(True)
switcher.show()
sys.exit(app.exec_())
问题是您没有更改 QPropertyAnimation
的地址。您不能使用 {your QPropertyAnimation}.setDirection = {some value}
,而是 {your QPropertyAnimation}.setDirection({some value})
。您必须更改为
@pyqtSlot(bool, name='animate')
def animate(self, checked):
self.animation.setDirection(QPropertyAnimation.Forward if checked else QPropertyAnimation.Backward)
self.animation.start()
PyQt5 中的实现
from PyQt5.QtCore import Qt, pyqtSlot, QObject, QPropertyAnimation, QEasingCurve, QRectF, pyqtProperty, QSize
from PyQt5.QtGui import QLinearGradient, QGradient, QPalette, QPainter, QBrush, QPen
from PyQt5.QtWidgets import QApplication, QAbstractButton
class QSlideSwitchPrivate(QObject):
def __init__(self, q):
QObject.__init__(self)
self._position = 0
self._sliderShape = QRectF()
self._gradient = QLinearGradient()
self._gradient.setSpread(QGradient.PadSpread)
self._qPointer = q
self.animation = QPropertyAnimation(self)
self.animation.setTargetObject(self)
self.animation.setPropertyName(b"position")
self.animation.setStartValue(0)
self.animation.setEndValue(1)
self.animation.setDuration(300)
self.animation.setEasingCurve(QEasingCurve.InOutExpo)
def __del__(self):
del self.animation
@pyqtProperty(float)
def position(self):
return self._position
@position.setter
def position(self, value):
self._position = value
self._qPointer.repaint()
def drawSlider(self, painter):
margin = 3
r = self._qPointer.rect().adjusted(0, 0, -1, -1)
dx = (r.width() - self._sliderShape.width()) * self._position
sliderRect = self._sliderShape.translated(dx, 0)
painter.setPen(Qt.NoPen)
# basic settings
shadow = self._qPointer.palette().color(QPalette.Dark)
light = self._qPointer.palette().color(QPalette.Light)
button = self._qPointer.palette().color(QPalette.Button)
# draw background
# draw outer background
self._gradient.setColorAt(0, shadow.darker(130))
self._gradient.setColorAt(1, light.darker(130))
self._gradient.setStart(0, r.height())
self._gradient.setFinalStop(0, 0)
painter.setBrush(self._gradient)
painter.drawRoundedRect(r, 15, 15)
# draw background
# draw inner background
self._gradient.setColorAt(0, shadow.darker(140))
self._gradient.setColorAt(1, light.darker(160))
self._gradient.setStart(0, 0)
self._gradient.setFinalStop(0, r.height())
painter.setBrush(self._gradient)
painter.drawRoundedRect(r.adjusted(margin, margin, -margin, -margin), 15, 15)
# draw slider
self._gradient.setColorAt(0, button.darker(130))
self._gradient.setColorAt(1, button)
# draw outer slider
self._gradient.setStart(0, r.height())
self._gradient.setFinalStop(0, 0)
painter.setBrush(self._gradient)
painter.drawRoundedRect(sliderRect.adjusted(margin, margin, -margin, -margin), 10, 15)
# draw inner slider
self._gradient.setStart(0, 0)
self._gradient.setFinalStop(0, r.height())
painter.setBrush(self._gradient)
painter.drawRoundedRect(sliderRect.adjusted(2.5 * margin, 2.5 * margin, -2.5 * margin, - 2.5 * margin), 5, 15)
# draw text
if self.animation.state() == QPropertyAnimation.Running:
return # don't draw any text while animation is running
font = self._qPointer.font()
self._gradient.setColorAt(0, light)
self._gradient.setColorAt(1, shadow)
self._gradient.setStart(0, r.height() / 2.0 + font.pointSizeF())
self._gradient.setFinalStop(0, r.height() / 2.0 - font.pointSizeF())
painter.setFont(font)
painter.setPen(QPen(QBrush(self._gradient), 0))
if self._qPointer.isChecked():
painter.drawText(0, 0, int(r.width() / 2), r.height() - 1, Qt.AlignCenter, "ON")
else:
painter.drawText(int(r.width() / 2), 0, int(r.width() / 2), r.height() - 1, Qt.AlignCenter, "OFF")
def updateSliderRect(self, size):
self._sliderShape.setWidth(size.width() / 2.0)
self._sliderShape.setHeight(size.height() - 1.0)
@pyqtSlot(bool, name='animate')
def animate(self, checked):
self.animation.setDirection(QPropertyAnimation.Forward if checked else QPropertyAnimation.Backward)
self.animation.start()
class QSlideSwitch(QAbstractButton):
def __init__(self, parent=None):
super(QAbstractButton, self).__init__(parent)
self.d_ptr = QSlideSwitchPrivate(self)
self.clicked.connect(self.d_ptr.animate)
self.d_ptr.animation.finished.connect(self.update)
# def __del__(self):
# del self.d_ptr
def sizeHint(self):
return QSize(48, 28)
def hitButton(self, point):
return self.rect().contains(point)
def paintEvent(self, event):
painter = QPainter(self)
painter.setRenderHint(QPainter.Antialiasing)
self.d_ptr.drawSlider(painter)
def resizeEvent(self, event):
self.d_ptr.updateSliderRect(event.size())
self.repaint()
if __name__ == '__main__':
import sys
app = QApplication(sys.argv)
switcher = QSlideSwitch()
switcher.setCheckable(True)
switcher.show()
sys.exit(app.exec_())