Объяснение:
Чтобы понять проблему, необходимо проанализировать размер self.resizedBallPixmap
, используя следующий код:
def rotateBall(self):
print(self.resizedBallPixmap.size())
# ...
Вывод:
PyQt5.QtCore.QSize(50, 50)
PyQt5.QtCore.QSize(59, 58)
PyQt5.QtCore.QSize(70, 68)
PyQt5.QtCore.QSize(81, 80)
PyQt5.QtCore.QSize(94, 93)
PyQt5.QtCore.QSize(110, 108)
PyQt5.QtCore.QSize(128, 126)
PyQt5.QtCore.QSize(149, 147)
PyQt5.QtCore.QSize(173, 171)
PyQt5.QtCore.QSize(201, 199)
PyQt5.QtCore.QSize(233, 231)
PyQt5.QtCore.QSize(271, 268)
PyQt5.QtCore.QSize(314, 311)
...
Как видите, размер QPixmap меняется, и почему он меняется? потому что при вращении прямоугольника бывший вписанный прямоугольник должен быть больше, и что заставляет прямоугольник быть больше? Ну, размер QLabel недостаточен для рисования QPixmap, и он рисует только левую часть, заставляя пользователя наблюдать, как мяч продвигается.
Решение:
Решение состоит в том, что когда QPixmap вращается, обрезается и сохраняется только необходимая часть. Кроме того, каждое преобразование вращения генерирует искажение, поэтому не рекомендуется выполнять итерацию по тому же QPixmap, но поддерживать исходную QPixmap и увеличивать угол поворота.
class MainWindow(QMainWindow):
def __init__(self, *args, **kwargs):
# ...
self.ballLabel.move(0, 0)
<b>self.angle = 0</b>
def rotateBall(self):
<b>self.angle += self.ballRotation
pixmap = self.resizedBallPixmap.transformed(
QTransform().rotate(self.angle), Qt.FastTransformation
)
r = QtCore.QRect(self.resizedBallPixmap.rect())
r.moveCenter(pixmap.rect().center())
pixmap = pixmap.copy(r)
self.ballLabel.setPixmap(pixmap)</b>
Лучшее решение состоит в том, чтобы используйте элементы Qt Graphics Framework, такие как QGraphicsItems, который реализует вращение и перевод.
class MainWindow(QMainWindow):
def __init__(self, *args, **kwargs):
super(MainWindow, self).__init__(*args, **kwargs)
self.setWindowTitle("ball move")
self.setFixedSize(800, 500)
scene = QGraphicsScene()
scene.setSceneRect(QRectF(QPointF(), QSizeF(self.size())))
view = QGraphicsView(scene)
self.setCentralWidget(view)
self.setStyleSheet("background-color: black;border:none;")
pixmap = QPixmap("ball.png").scaled(
50, 50, Qt.KeepAspectRatio, Qt.FastTransformation
)
self.ballLabel = scene.addPixmap(pixmap)
self.ballLabel.setTransformOriginPoint(self.ballLabel.boundingRect().center())
class BallManager(QObject):
positionChanged = pyqtSignal(QPointF)
angleChanged = pyqtSignal(float)
def __init__(self, parent=None):
super(BallManager, self).__init__(parent)
self.pos = QPointF(0, 0)
self.angle = 0
self.vel = QPointF(2, 1)
self.rand = QPointF(*random.sample([1, 2, 3], 2))
self.step_angle = 10
self.timer = QTimer(interval=1000, timeout=self.ballMove)
self.timer.start()
def ballMove(self):
if (self.pos.x() + 50) > 800:
self.vel.setX(-1)
self.randX = QPointF(*random.sample([1, 2, 3], 2))
elif self.pos.x() < 0:
self.vel.setX(1)
self.rand = QPointF(*random.sample([1, 2, 3], 2))
elif (self.pos.y() + 50) > 500:
self.vel.setY(-1)
self.rand = QPointF(*random.sample([1, 2, 3], 2))
elif self.pos.y() < 0:
self.vel.setY(1)
self.rand = QPointF(*random.sample([1, 2, 3], 2))
self.pos += QPointF(self.vel.x() * self.rand.x(), self.vel.y() * self.rand.y())
self.angle += self.step_angle
self.positionChanged.emit(self.pos)
self.angleChanged.emit(self.angle)
if __name__ == "__main__":
app = QApplication([])
main_window = MainWindow()
main_window.show()
manager = BallManager()
manager.positionChanged.connect(main_window.ballLabel.setPos)
manager.angleChanged.connect(main_window.ballLabel.setRotation)
app.exec_()