当 window 大小随绘画事件发生变化时,启用小部件如何移动?
how enable widget moved when window size changed with paint event?
我正在尝试创建一个小部件来为线条设置动画,当 windows 大小更改时,动画始终播放该大小。
我知道 PainterPath 总是相同的,但我没有任何简单的想法可以做?
from PyQt5.QtGui import *
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
class PathAnimation(QPropertyAnimation):
def __init__(self, path=QPainterPath(), object=None, property=None):
super().__init__(object, property)
self.path = path
def updateCurrentTime(self, currentTime):
easedProgress = self.easingCurve().valueForProgress(currentTime/self.duration())
pt = self.path.pointAtPercent(easedProgress)
self.updateCurrentValue(pt)
self.valueChanged.emit(pt)
class DemoB(QWidget):
def __init__(self):
super().__init__()
self.resize(400, 400)
self.button = QPushButton('test', self)
def mouseDoubleClickEvent(self, e):
self.ani = PathAnimation(self.path, self.button, b'pos')
self.ani.setDuration(2000)
self.ani.start()
def paintEvent(self, e):
painter = QPainter(self)
painter.begin(self)
painter.setWindow(0, 0, 400, 400)
self.path = QPainterPath()
self.path.cubicTo(QPointF(0, 400), QPointF(200, 0), QPointF(400, 400))
painter.drawPath( self.path )
painter.end()
app = QApplication([])
demo = DemoB()
demo.show()
app.exec()
抱歉,您的问题有点混乱。如果我理解正确,你想在每次 window 调整大小时更新路径。
问题是每当绘制 window 时,您都会创建一个 new self.path
对象,一旦绘制 window 也会发生这种情况第一次,因此您为 属性 创建的 QPainterPath 对象实际上并未更新。
您应该仅在 window 调整大小时更新路径,在 resizeEvent()
.
内
请记住,您只能从 Qt 5.13(去年 6 月发布)更新现有路径,否则您必须创建一个新路径并确保更新 path
属性 你的动画也是。
from PyQt5.QtGui import *
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
# find if Qt version is >= 5.13
QtVersion = [int(v) for v in QT_VERSION_STR.split('.')]
CanClearPath = QtVersion[0] == 5 and QtVersion[1] >= 13
class PathAnimation(QPropertyAnimation):
def __init__(self, path=QPainterPath(), object=None, property=None):
super().__init__(object, property)
self.path = path
def updateCurrentTime(self, currentTime):
easedProgress = self.easingCurve().valueForProgress(currentTime/self.duration())
pt = self.path.pointAtPercent(easedProgress)
self.updateCurrentValue(pt)
self.valueChanged.emit(pt)
class DemoB(QWidget):
def __init__(self):
super().__init__()
self.resize(400, 400)
self.button = QPushButton('test', self)
self.path = QPainterPath()
self.ani = PathAnimation(self.path, self.button, b'pos')
self.ani.setDuration(2000)
def mouseDoubleClickEvent(self, e):
if self.ani.state():
return
self.ani.setStartValue(QPointF(0, 0))
self.ani.start()
def resizeEvent(self, event):
if CanClearPath:
self.path.clear()
else:
self.path = QPainterPath()
rect = self.rect()
# use the current size to update the path positions
self.path.cubicTo(rect.bottomLeft(),
QPointF(rect.center().x(), 0), rect.bottomRight())
# update the final value!
self.ani.setEndValue(rect.bottomRight())
if not CanClearPath:
self.ani.path = self.path
def paintEvent(self, e):
painter = QPainter(self)
# no need to begin() a painter if you already gave it its argument
painter.drawPath(self.path)
if __name__ == '__main__':
import sys
app = QApplication(sys.argv)
demo = DemoB()
demo.show()
sys.exit(app.exec())
另一种可能性是完全避免 QPropertyAnimation 子类,使用从 0.0
到 1.0
的私有 属性,为此创建一个 QPropertyAnimation,然后连接它的 valueChanged
向使用 pointAtPercent 计算位置的函数发出信号,然后移动按钮。
class DemoB(QWidget):
def __init__(self):
super().__init__()
self.resize(400, 400)
self.button = QPushButton('test', self)
self.path = QPainterPath()
# create an internal property
self.setProperty('pathPercent', 0.0)
self.ani = QPropertyAnimation(self, b'pathPercent')
self.ani.setEndValue(1.0)
self.ani.setDuration(2000)
self.ani.valueChanged.connect(self.updatePosition)
def mouseDoubleClickEvent(self, e):
if self.ani.state():
return
# reset the property to 0 so that it is restarted from the beginning
self.setProperty('pathPercent', 0.0)
self.ani.start()
def updatePosition(self, pos):
self.button.move(self.path.pointAtPercent(pos).toPoint())
def resizeEvent(self, event):
# recreate/update the current path, based on the new window size.
if CanClearPath:
self.path.clear()
else:
self.path = QPainterPath()
rect = self.rect()
self.path.cubicTo(rect.bottomLeft(),
QPointF(rect.center().x(), 0), rect.bottomRight())
def paintEvent(self, e):
painter = QPainter(self)
painter.drawPath(self.path)
我正在尝试创建一个小部件来为线条设置动画,当 windows 大小更改时,动画始终播放该大小。
我知道 PainterPath 总是相同的,但我没有任何简单的想法可以做?
from PyQt5.QtGui import *
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
class PathAnimation(QPropertyAnimation):
def __init__(self, path=QPainterPath(), object=None, property=None):
super().__init__(object, property)
self.path = path
def updateCurrentTime(self, currentTime):
easedProgress = self.easingCurve().valueForProgress(currentTime/self.duration())
pt = self.path.pointAtPercent(easedProgress)
self.updateCurrentValue(pt)
self.valueChanged.emit(pt)
class DemoB(QWidget):
def __init__(self):
super().__init__()
self.resize(400, 400)
self.button = QPushButton('test', self)
def mouseDoubleClickEvent(self, e):
self.ani = PathAnimation(self.path, self.button, b'pos')
self.ani.setDuration(2000)
self.ani.start()
def paintEvent(self, e):
painter = QPainter(self)
painter.begin(self)
painter.setWindow(0, 0, 400, 400)
self.path = QPainterPath()
self.path.cubicTo(QPointF(0, 400), QPointF(200, 0), QPointF(400, 400))
painter.drawPath( self.path )
painter.end()
app = QApplication([])
demo = DemoB()
demo.show()
app.exec()
抱歉,您的问题有点混乱。如果我理解正确,你想在每次 window 调整大小时更新路径。
问题是每当绘制 window 时,您都会创建一个 new self.path
对象,一旦绘制 window 也会发生这种情况第一次,因此您为 属性 创建的 QPainterPath 对象实际上并未更新。
您应该仅在 window 调整大小时更新路径,在 resizeEvent()
.
请记住,您只能从 Qt 5.13(去年 6 月发布)更新现有路径,否则您必须创建一个新路径并确保更新 path
属性 你的动画也是。
from PyQt5.QtGui import *
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
# find if Qt version is >= 5.13
QtVersion = [int(v) for v in QT_VERSION_STR.split('.')]
CanClearPath = QtVersion[0] == 5 and QtVersion[1] >= 13
class PathAnimation(QPropertyAnimation):
def __init__(self, path=QPainterPath(), object=None, property=None):
super().__init__(object, property)
self.path = path
def updateCurrentTime(self, currentTime):
easedProgress = self.easingCurve().valueForProgress(currentTime/self.duration())
pt = self.path.pointAtPercent(easedProgress)
self.updateCurrentValue(pt)
self.valueChanged.emit(pt)
class DemoB(QWidget):
def __init__(self):
super().__init__()
self.resize(400, 400)
self.button = QPushButton('test', self)
self.path = QPainterPath()
self.ani = PathAnimation(self.path, self.button, b'pos')
self.ani.setDuration(2000)
def mouseDoubleClickEvent(self, e):
if self.ani.state():
return
self.ani.setStartValue(QPointF(0, 0))
self.ani.start()
def resizeEvent(self, event):
if CanClearPath:
self.path.clear()
else:
self.path = QPainterPath()
rect = self.rect()
# use the current size to update the path positions
self.path.cubicTo(rect.bottomLeft(),
QPointF(rect.center().x(), 0), rect.bottomRight())
# update the final value!
self.ani.setEndValue(rect.bottomRight())
if not CanClearPath:
self.ani.path = self.path
def paintEvent(self, e):
painter = QPainter(self)
# no need to begin() a painter if you already gave it its argument
painter.drawPath(self.path)
if __name__ == '__main__':
import sys
app = QApplication(sys.argv)
demo = DemoB()
demo.show()
sys.exit(app.exec())
另一种可能性是完全避免 QPropertyAnimation 子类,使用从 0.0
到 1.0
的私有 属性,为此创建一个 QPropertyAnimation,然后连接它的 valueChanged
向使用 pointAtPercent 计算位置的函数发出信号,然后移动按钮。
class DemoB(QWidget):
def __init__(self):
super().__init__()
self.resize(400, 400)
self.button = QPushButton('test', self)
self.path = QPainterPath()
# create an internal property
self.setProperty('pathPercent', 0.0)
self.ani = QPropertyAnimation(self, b'pathPercent')
self.ani.setEndValue(1.0)
self.ani.setDuration(2000)
self.ani.valueChanged.connect(self.updatePosition)
def mouseDoubleClickEvent(self, e):
if self.ani.state():
return
# reset the property to 0 so that it is restarted from the beginning
self.setProperty('pathPercent', 0.0)
self.ani.start()
def updatePosition(self, pos):
self.button.move(self.path.pointAtPercent(pos).toPoint())
def resizeEvent(self, event):
# recreate/update the current path, based on the new window size.
if CanClearPath:
self.path.clear()
else:
self.path = QPainterPath()
rect = self.rect()
self.path.cubicTo(rect.bottomLeft(),
QPointF(rect.center().x(), 0), rect.bottomRight())
def paintEvent(self, e):
painter = QPainter(self)
painter.drawPath(self.path)