You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PyQt5鼠标悬浮控件缩放:自定义缩放原点的实现疑问

解决PyQt5控件自定义缩放原点的问题

不需要使用特定类,只需要在缩放动画的同时调整控件的位置,就能实现围绕自定义原点(如右上、左下、顶部中心等)的缩放效果。核心思路是:缩放时根据目标原点计算控件位置的偏移量,同步动画控件的尺寸和位置,让指定原点保持不动。

修改后的实现代码

from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *

# 定义缩放原点选项
class ScaleOrigin:
    TopLeft = 0
    TopCenter = 1
    TopRight = 2
    BottomLeft = 3
    BottomCenter = 4
    BottomRight = 5

class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setFixedSize(600, 600)
        
        widget = QWidget()
        self.setCentralWidget(widget)
        layout = QVBoxLayout()
        widget.setLayout(layout)
        
        # 示例:创建不同缩放原点的控件
        items = [
            ("顶部中心", ScaleOrigin.TopCenter),
            ("右上", ScaleOrigin.TopRight),
            ("左下", ScaleOrigin.BottomLeft)
        ]
        for name, origin in items:
            item = MyItem(scale_origin=origin)
            layout.addWidget(item, Qt.AlignCenter)
            label = QLabel(name)
            layout.addWidget(label, Qt.AlignCenter)

class MyItem(QLabel):
    def __init__(self, scale_origin=ScaleOrigin.TopLeft):
        super().__init__()
        self.base_size = QSize(30, 30)
        self.scale_factor = 10
        self.scale_origin = scale_origin
        
        self.setMinimumSize(self.base_size)
        self.resize(self.base_size)
        self.setStyleSheet('background: blue')
        
        self._enlarged = False
        # 创建并行动画组,同步尺寸和位置动画
        self.anim_group = QParallelAnimationGroup()
        
        # 尺寸动画
        self.size_anim = QPropertyAnimation(self, b'size')
        self.size_anim.setDuration(200)
        self.anim_group.addAnimation(self.size_anim)
        
        # 位置动画
        self.pos_anim = QPropertyAnimation(self, b'pos')
        self.pos_anim.setDuration(200)
        self.anim_group.addAnimation(self.pos_anim)

    def enterEvent(self, event):
        self._enlarged = False
        self.start_scale_anim()

    def leaveEvent(self, event):
        self._enlarged = True
        self.start_scale_anim()

    def start_scale_anim(self):
        if self._enlarged:
            target_size = self.base_size
        else:
            target_size = QSize(self.base_size.width() * self.scale_factor, 
                               self.base_size.height() * self.scale_factor)
        
        # 计算位置偏移量,让指定原点保持不动
        current_pos = self.pos()
        current_size = self.size()
        dx = 0
        dy = 0
        
        if self.scale_origin == ScaleOrigin.TopCenter:
            dx = (current_size.width() - target_size.width()) / 2
        elif self.scale_origin == ScaleOrigin.TopRight:
            dx = current_size.width() - target_size.width()
        elif self.scale_origin == ScaleOrigin.BottomLeft:
            dy = current_size.height() - target_size.height()
        elif self.scale_origin == ScaleOrigin.BottomCenter:
            dx = (current_size.width() - target_size.width()) / 2
            dy = current_size.height() - target_size.height()
        elif self.scale_origin == ScaleOrigin.BottomRight:
            dx = current_size.width() - target_size.width()
            dy = current_size.height() - target_size.height()
        
        target_pos = QPoint(current_pos.x() + dx, current_pos.y() + dy)
        
        # 设置动画目标值
        self.size_anim.setEndValue(target_size)
        self.pos_anim.setEndValue(target_pos)
        self.anim_group.start()

if __name__ == '__main__':
    app = QApplication([])
    window = MainWindow()
    window.show()
    app.exec()

关键实现说明

  • 定义ScaleOrigin枚举,方便指定不同的缩放原点。
  • 使用QParallelAnimationGroup同时动画控件的size和pos属性,确保缩放和位置调整同步进行,避免卡顿。
  • 根据选定的缩放原点,计算位置偏移量:比如选择顶部中心时,缩放后控件的水平中点要和原位置中点重合,所以需要向左偏移(原宽度-新宽度)/2的距离;选择右上时,需要向左偏移(原宽度-新宽度)的距离,垂直位置不变。
  • 进入/离开事件中切换缩放状态,触发对应的动画。

内容的提问来源于stack exchange,提问作者coder

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.20 15:17:52