I'm trying to code a widget that slightly increases in size on mouse-over and decreases when the mouse leaves again.
This is what I have come up with so far:
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from random import randrange
class MainWindow(QMainWindow):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.setFixedSize(500, 500)
cent_widget = QWidget()
self.setCentralWidget(cent_widget)
layout = QVBoxLayout()
cent_widget.setLayout(layout)
layout.addWidget(MyItem(), Qt.AlignCenter,
alignment=Qt.AlignCenter)
class MyItem(QLabel):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.setBaseSize(200, 250)
self.setMinimumSize(self.baseSize())
self.resize(self.baseSize())
self.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
self.setStyleSheet('background: #{:02x}{:02x}{:02x}'.format(
randrange(255), randrange(255), randrange(255)
))
# Animation
self._enlarged = False
self.zoom_factor = 1.2
self.anim = QPropertyAnimation(self, b'size')
self.anim.setEasingCurve(QEasingCurve.InOutSine)
self.anim.setDuration(250)
def enterEvent(self, event: QEvent) -> None:
self.resize_anim()
self._enlarged = True
def leaveEvent(self, event: QEvent) -> None:
self.resize_anim()
self._enlarged = False
def resize_anim(self):
if self._enlarged:
new_size = self.baseSize()
else:
new_size = QSize(
int(self.baseSize().width() * self.zoom_factor),
int(self.baseSize().height() * self.zoom_factor)
)
self.anim.setEndValue(new_size)
self.anim.start()
if __name__ == '__main__':
app = QApplication([])
window = MainWindow()
window.show()
app.exec()
It's almost working the way I want, my only problem is that the widget gets resized from the top-left corner instead of from the center.
How can I change that?
Instead of animating using the size property you should use the geometry property as it is relative to the parent widget, so you can animate its geometry making the center remain invariant.
from PyQt5.QtCore import (
QAbstractAnimation,
QEasingCurve,
QEvent,
QPropertyAnimation,
QRect,
Qt,
)
from PyQt5.QtGui import QColor
from PyQt5.QtWidgets import (
QApplication,
QLabel,
QMainWindow,
QSizePolicy,
QVBoxLayout,
QWidget,
)
import random
class MainWindow(QMainWindow):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.setFixedSize(500, 500)
cent_widget = QWidget()
self.setCentralWidget(cent_widget)
layout = QVBoxLayout(cent_widget)
layout.addWidget(MyItem(), alignment=Qt.AlignCenter)
class MyItem(QLabel):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.setBaseSize(200, 250)
self.setMinimumSize(self.baseSize())
self.resize(self.baseSize())
self.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
self.setStyleSheet(
"background: {}".format(QColor(*random.sample(range(255), 3)).name())
)
# Animation
self.zoom_factor = 1.2
self.anim = QPropertyAnimation(self, b"geometry")
self.anim.setEasingCurve(QEasingCurve.InOutSine)
self.anim.setDuration(250)
def enterEvent(self, event: QEvent) -> None:
initial_rect = self.geometry()
final_rect = QRect(
0,
0,
int(initial_rect.width() * self.zoom_factor),
int(initial_rect.height() * self.zoom_factor),
)
final_rect.moveCenter(initial_rect.center())
self.anim.setStartValue(initial_rect)
self.anim.setEndValue(final_rect)
self.anim.setDirection(QAbstractAnimation.Forward)
self.anim.start()
def leaveEvent(self, event: QEvent) -> None:
self.anim.setDirection(QAbstractAnimation.Backward)
self.anim.start()
if __name__ == "__main__":
app = QApplication([])
window = MainWindow()
window.show()
app.exec()