Dre*_*m59 3 qt pyqt paintevent pyside pyqt5
我正在尝试创建自定义动画按钮我找到了此页面:按钮示例
我喜欢这个网站上的 3 和 19。我试过做3个,但不一样。有人能帮我吗?
我的网站上第三个按钮的代码:
# -*- coding: utf-8 -*-
import sys, os, time, math
from PySide6 import QtCore, QtWidgets, QtGui
from PySide6.QtWidgets import *
from PySide6.QtCore import *
from PySide6.QtGui import *
class EButton3(QPushButton):
AnimateEnabled = True
Radius = 10
_m_Text = ""
def __init__(self, parent=None):
super(EButton3, self).__init__(None)
self.enterEvent = self.Custom_enterEvent
self.leaveEvent = self.Custom_leaveEvent
self.setText("Button")
def getText(self):
return self._m_Text
def setText(self, Text):
self._m_Text = Text
self.update()
_m_hover=False
def isHover(self):
return self._m_hover
def paintEvent(self, event: QPaintEvent):
ret = None #QPushButton.paintEvent(self, event)
painter = QPainter(self)
painter.setRenderHint(QPainter.Antialiasing)
path, path2 = QPainterPath(), QPainterPath()
BaseBackground, BaseBackgroundHover = QColor(Qt.black), QColor(22,2,22)
BaseForeground, BaseForegroundHover = QColor(Qt.white), QColor(Qt.black)
painter.setBrush(QBrush(BaseBackground if not self.isHover() else BaseBackgroundHover))
painter.setPen(Qt.NoPen)
rect = QRectF(0, 0, self.width(), self.height())
path.addRoundedRect(rect, self.Radius, self.Radius)
painter.drawPath(path)
painter.setPen(BaseForeground if not self.isHover() else BaseForegroundHover)
if self.AnimateEnabled:
painter.setBrush(QBrush(QColor(231, 231, 231)))
anval = self.AnimateVal / 100
polygon = QPolygonF([
QPoint(self.width() * anval, 0),
QPoint(0, 0),
QPoint(0, self.height()),
QPoint((self.width() + 10) * math.sin(anval / 100 * 180), self.height())
])
painter.setClipPath(path)
path2.addPolygon(polygon)
painter.drawPath(path2)
painter.drawText(self.rect(), Qt.AlignCenter, self.getText())
return ret
_animateVal = 0
def setAnimateVal(self, val):
self._animateVal = val
def getAnimateVal(self):
return self._animateVal
AnimateVal = QtCore.Property(int, getAnimateVal, setAnimateVal)
temps = []
def Custom_enterEvent(self, event) -> None:
self._m_hover = True
step2_ani = QPropertyAnimation(self, b'AnimateVal')
step2_ani.setStartValue(self.getAnimateVal())
step2_ani.setEndValue(100)
step2_ani.setEasingCurve(QEasingCurve.InQuad)
step2_ani.setDuration(500)
self.temps.append(step2_ani)
def valChanged():
self.update()
def finished():
self.AnimateVal = 100
step2_ani.valueChanged.connect(valChanged)
step2_ani.finished.connect(finished)
step2_ani.start()
return QPushButton.enterEvent(self, event)
def Custom_leaveEvent(self, event) -> None:
self._m_hover = False
step2_ani = QPropertyAnimation(self, b'AnimateVal')
self.temps.append(step2_ani) # we need to store it or self.step_ani2 = ... else it will not start
step2_ani.setStartValue(self.getAnimateVal())
step2_ani.setEndValue(0)
step2_ani.setEasingCurve(QEasingCurve.OutCubic)
step2_ani.setDuration(500)
def valChanged():
self.update()
def finished():
self.AnimateVal = 0
step2_ani.valueChanged.connect(valChanged)
step2_ani.finished.connect(finished)
step2_ani.start()
return QPushButton.leaveEvent(self, event)
if __name__ == "__main__":
app = QApplication(sys.argv)
wind = QMainWindow()
wind.setStyleSheet("QMainWindow{background-color:rgb(247,247,250)}")
wind.resize(150, 80)
wid = QWidget()
lay = QHBoxLayout(wid)
lay.setAlignment(Qt.AlignCenter)
mycustombutton = EButton3()
mycustombutton.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
lay.addWidget(mycustombutton)
wind.setCentralWidget(wid)
wind.show()
sys.exit(app.exec())
Run Code Online (Sandbox Code Playgroud)
我的 19 号代码:按钮
# -*- coding: utf-8 -*-
import sys, os, time, math
from PySide6 import QtCore, QtWidgets, QtGui
from PySide6.QtWidgets import *
from PySide6.QtCore import *
from PySide6.QtGui import *
class EButton19(QPushButton):
AnimateEnabled = True
Radius = 10
_m_Text = ""
def __init__(self, parent=None):
super(EButton19, self).__init__(None)
self.enterEvent = self.Custom_enterEvent
self.leaveEvent = self.Custom_leaveEvent
self.setText("Button")
self.propertyanimation = QPropertyAnimation(self, b'AnimateVal')
self.propertyanimation.setDuration(350)
def getText(self):
return self._m_Text
def setText(self, Text):
self._m_Text = Text
self.update()
_m_hover=False
def isHover(self):
return self._m_hover
def paintEvent(self, event: QPaintEvent):
painter = QPainter(self)
painter.setRenderHint(QPainter.Antialiasing)
BaseBackground, BaseBackgroundHover = QColor(231,231,231), QColor(Qt.black)
BaseForeground, BaseForegroundHover = QColor(Qt.black), QColor(Qt.white)
path, path2 = QPainterPath(), QPainterPath()
painter.setBrush(QBrush(BaseBackground if not self.isHover() else BaseBackgroundHover))
painter.setPen(Qt.NoPen)
rect = QRectF(0, 0, self.width(), self.height())
anval = self.AnimateVal / 100
padding = 10
rect = rect.adjusted(-padding * anval, -padding * anval, padding * anval, padding * anval)
path.addRoundedRect(rect.adjusted(padding / 2, padding, -padding / 2, -padding), self.Radius, self.Radius)
painter.drawPath(path)
if self.AnimateEnabled and self.isHover():
painter.setBrush(QBrush(QColor(0, 0, 0)))
painter.setClipPath(path)
painter.setPen(Qt.black)
radiusEffect = 75
path2.addEllipse(self.rect().center(), radiusEffect * anval, radiusEffect * anval)
painter.drawPath(path2)
painter.setPen(BaseForeground if not self.isHover() else BaseForegroundHover)
painter.drawText(self.rect(), Qt.AlignCenter, self.getText())
_animateVal = 0
def setAnimateVal(self, val):
self._animateVal = val
def getAnimateVal(self):
return self._animateVal
AnimateVal = QtCore.Property(int, getAnimateVal, setAnimateVal)
def Custom_enterEvent(self, event):
self._m_hover = True
self.propertyanimation.stop()
self.propertyanimation.setStartValue(self.getAnimateVal())
self.propertyanimation.setEndValue(100)
self.propertyanimation.setEasingCurve(QEasingCurve.InQuad)
def valChanged():
self.update()
def finished():
self.AnimateVal = 100
self.propertyanimation.valueChanged.connect(valChanged)
self.propertyanimation.finished.connect(finished)
self.propertyanimation.start()
return QPushButton.enterEvent(self, event)
def Custom_leaveEvent(self, event) -> None:
self._m_hover = False
self.propertyanimation.stop()
self.propertyanimation.setStartValue(self.getAnimateVal())
self.propertyanimation.setEndValue(0)
self.propertyanimation.setEasingCurve(QEasingCurve.OutCubic)
def valChanged():
self.update()
def finished():
self.AnimateVal = 0
self.propertyanimation.valueChanged.connect(valChanged)
self.propertyanimation.finished.connect(finished)
self.propertyanimation.start()
return QPushButton.leaveEvent(self, event)
if __name__ == "__main__":
app = QApplication(sys.argv)
wind = QMainWindow()
wind.setStyleSheet("QMainWindow{background-color:rgb(247,247,250)}")
wind.resize(150, 80)
wid = QWidget()
lay = QHBoxLayout(wid)
lay.setAlignment(Qt.AlignCenter)
mycustombutton = EButton19()
mycustombutton.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
lay.addWidget(mycustombutton)
wind.setCentralWidget(wid)
wind.show()
sys.exit(app.exec())
Run Code Online (Sandbox Code Playgroud)
我的代码外观很糟糕(如果你运行它,你就会看到)。我需要帮助!(适用于第 3 个和第 19 个按钮)
谢谢!
您的代码的主要问题是您使用基于浮点的矩形进行剪切,但绘画仍然发生在概念上整数的坐标中,并且也忽略了画笔宽度。
您还使您的代码比应有的更加复杂,没有考虑使用不同命名的方法“覆盖”进入/离开事件,而不是正确覆盖基本实现。
我建议采用一种更干净的方法,最重要的是,考虑正确的剪切坐标,并且还使用单个动画而不是不断创建新动画(这最终可能导致不必要的内存使用,因为这些动画在完成后不会被销毁。
重要的部分是setClipPath()
使用IntersectClip
参数,因此只会为合并路径的结果设置剪切(仅使用它们的公共区域)。
最后,并不总是需要为 Qt 动画创建自定义属性:QVariantAnimation通常就足够了(并且高效,除非过度使用它们),因为您只在需要时访问它,而不是调用 setter Property
。
在讨论建议的解决方案之前,还有一些其他注意事项:
class Button(QtWidgets.QPushButton):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.backgroundColors = (
QtGui.QColor(QtCore.Qt.black),
QtGui.QColor(QtCore.Qt.lightGray)
)
self.foregroundColors = (
QtGui.QColor(QtCore.Qt.white),
QtGui.QColor(QtCore.Qt.black)
)
font = self.font()
font.setBold(True)
self.setFont(font)
self.hoverAnimation = QtCore.QVariantAnimation(self)
# NOTE: both start and end values *must* be floats, otherwise the
# animation will just "jump" from 0 to 1 and vice versa!
self.hoverAnimation.setStartValue(0.)
self.hoverAnimation.setEndValue(1.)
self.hoverAnimation.setEasingCurve(QtCore.QEasingCurve.OutCubic)
self.hoverAnimation.setDuration(400)
self.hoverAnimation.valueChanged.connect(self.update)
def enterEvent(self, event):
super().enterEvent(event)
self.hoverAnimation.setDirection(self.hoverAnimation.Forward)
self.hoverAnimation.start()
def leaveEvent(self, event):
super().leaveEvent(event)
self.hoverAnimation.setDirection(self.hoverAnimation.Backward)
self.hoverAnimation.start()
def paintEvent(self, event):
qp = QtGui.QPainter(self)
qp.setRenderHint(qp.Antialiasing)
qp.save()
radius = max(4, min(self.height(), self.width()) * .125)
clipRect = QtCore.QRectF(self.rect().adjusted(0, 0, -1, -1))
borderPath = QtGui.QPainterPath()
borderPath.addRoundedRect(clipRect, radius, radius)
qp.setClipPath(borderPath)
qp.fillRect(self.rect(), self.backgroundColors[0])
qp.setPen(self.foregroundColors[0])
qp.drawText(self.rect(),
QtCore.Qt.AlignCenter|QtCore.Qt.TextShowMnemonic, self.text())
aniValue = self.hoverAnimation.currentValue()
if aniValue:
# use an arbitrary "center" for the radius, based on the widget size
extent = min(self.height(), self.width()) * 3
angle = atan(extent / self.width())
reference = cos(angle) * (extent + self.width())
x = self.width() - reference
ratio = 1 - aniValue
hoverPath = QtGui.QPainterPath()
hoverPath.moveTo(x, 0)
hoverPath.lineTo(self.width() - reference * ratio, 0)
hoverPath.lineTo(self.width(), extent)
hoverPath.lineTo(x, extent)
qp.setClipPath(hoverPath, QtCore.Qt.IntersectClip)
qp.fillRect(self.rect(), self.backgroundColors[1])
qp.setPen(self.foregroundColors[1])
qp.drawText(self.rect(), QtCore.Qt.AlignCenter|QtCore.Qt.TextShowMnemonic, self.text())
qp.restore()
qp.translate(.5, .5)
qp.drawRoundedRect(clipRect, radius, radius)
Run Code Online (Sandbox Code Playgroud)
注意:上面的实现还不完美(它有一些非常宽和短的按钮问题。我最终会尽快更新这个答案,只需将代码视为概念参考即可。
归档时间: |
|
查看次数: |
535 次 |
最近记录: |