QT之头像剪裁效果实现

[复制链接]
发表于 2025-7-1 11:36:13 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

×
源码地址,环境:QT5.15,MinGW32位

效果演示



导入图片

  1.     QPixmap m_srcPix;
  2.     QPixmap m_scaledPix;
  3.     //从文件导入图片
  4.     m_srcPix.load("D:\\Jolly\\A_0voice_chat\\chapter_explanation\\PictureEdit_demo\\PictureEdit\\images\\1.png");
  5.     //把导入的图片截取到窗口大小
  6.     m_scaledPix = m_srcPix.scaled(ui->label->width(), ui->label->height());
  7.     //在窗口显示图片
  8.     ui->label->setPixmap(m_scaledPix);
复制代码
设置剪裁地域

  1.     //裁剪头像活动窗口
  2.     //设置透明
  3.     this->setWindowFlags(Qt::FramelessWindowHint);
  4.     //设置矩形区域,整个窗口
  5.     this->setGeometry(0, 0, parentWidget()->width(), parentWidget()->height());
  6.         CutDialog *m_cutDialog;
  7.     //头像剪切窗口
  8.     m_cutDialog = new CutDialog(this);
  9.     m_cutDialog->show();
复制代码
创建剪裁小窗口

  1. CutDialog::CutDialog(QWidget *parent) :
  2.     QWidget(parent)
  3. {
  4.     setGeometry(0,0, 150, 150);
  5.     m_mouseDown = false;
  6. }
复制代码
重写剪裁小窗口的鼠标事件

mousePressEvent

  1. void CutDialog::mousePressEvent(QMouseEvent *event)
  2. {
  3.     //获取鼠标按下时的位置
  4.     m_startPoint = event->pos();
  5.     //判断按下的是否是鼠标左键
  6.     m_mouseDown = event->button() == Qt::LeftButton;
  7. }
复制代码
mouseMoveEvent

要是没有启用鼠标追踪,mouseMoveEvent 只有在鼠标按键被按下并且鼠标移动时才会触发,而且是在mousePressEvent触发之后。
当启用鼠标追踪后,不管鼠标按键是否被按下,只要鼠标移动,mouseMoveEvent就会触发
  1. void CutDialog::mouseMoveEvent(QMouseEvent *event)
  2. {
  3.     //获取鼠标移动以后的位置
  4.     QPoint dragPoint = event->pos();
  5.     if (m_mouseDown) {
  6.         //pos保存小部件在其父部件中的位置
  7.         QPoint p = QPoint(
  8.             //pos() 是对话框在父窗口中的左上角坐标
  9.             //dragPoint - m_startPoint 计算鼠标移动的偏移量
  10.             //原理: 拖动点相对于对话框的位置保持不变(如从(10,10)点开始拖动,移动后仍抓住该点)
  11.             pos().x()+dragPoint.x() - m_startPoint.x(), // 水平方向
  12.             pos().y()+dragPoint.y()-m_startPoint.y()    // 垂直方向
  13.         );
  14.         QPoint dragEndge = p;
  15.         dragEndge.setX(p.x() + rect().width());   // 对话框右下角X坐标
  16.         dragEndge.setY(p.y() + rect().height());  // 对话框右下角Y坐标
  17.         //左上角约束,保证小窗口左上角在父窗口范围内
  18.         p.setX(p.x() < 0 ? 0 : p.x());
  19.         p.setY(p.y() < 0 ? 0 : p.y());
  20.         //右下角约束
  21.         // 确保右下角X ≤ 父窗口宽度
  22.         p.setX(dragEndge.x() > parentWidget()->width()
  23.                    ? parentWidget()->width() - rect().width()
  24.                    : p.x());
  25.         // 确保右下角Y ≤ 父窗口高度
  26.         p.setY(dragEndge.y() > parentWidget()->height()
  27.                    ? parentWidget()->height() - rect().height()
  28.                    : p.y());
  29.         //QWidget::move() 对窗口部件的位置进行设置
  30.         move(p);
  31. /*
  32. move函数原型
  33. void move(int x, int y);
  34. void move(const QPoint &pos);
  35. */
  36.     }
  37. }
复制代码
mouseReleaseEvent

开释鼠标时将m_mouseDown 设置为false,避免鼠标右键或其他案件误触发mouseMoveEvent
  1. void CutDialog::mouseReleaseEvent(QMouseEvent *event)
  2. {
  3.     m_mouseDown = false;
  4. }
复制代码
小窗口移动触发父窗口的重绘事件

paintEvent调用机会:
​​首次表现窗口时​​
当 PhotoShotDialog 首次表现(例如通过 show() 或 exec())时,系统会自动触发 paintEvent 进行初始绘制。
​​窗口需要重绘时​​
窗口被其他窗口遮挡后重新暴露出来
窗口内容发生变化(如子窗口移动、尺寸变化)
调用 update() 或 repaint() 方法强制重绘
​​子窗口移动时(关键)​​
当用户拖动 CutDialog时:
CutDialog::mouseMoveEvent() 中调用了 move§ 移动裁剪框
移动利用会​​自动触发父窗口(PhotoShotDialog)的重绘​​,由于:
子窗口位置变化导致父窗口的可看法区需要更新
系统自动发送重绘事件到父窗口
  1. void PhotoShotDialog::paintEvent(QPaintEvent *event)
  2. {
  3.     QPainterPath painterPath;
  4.     QPainterPath p;
  5.     p.addRect(x(),y(),this->rect().width(), this->rect().height()); //裁剪头像活动窗口 (蓝色矩形)
  6.     //QWidget::geometry()返回一个 QRect 对象。这个对象包含了窗口部件的位置和大小信息
  7.     painterPath.addRect(m_cutDialog->geometry()); //头像剪切窗口 (紫色矩形)
  8.     QPainterPath drawPath = p.subtracted(painterPath); //subtracted 获取除了painterPath区域以外的窗口
  9.     QPainter painter(this);
  10.     painter.setOpacity(0.6); //设置Qt控件透明度 0表示全透明,1表示不透明
  11.     painter.fillPath(drawPath, QBrush(Qt::black));
  12. }
复制代码
剪裁效果实现

  1. void PictureEdit::on_pushButton_clicked()
  2. {
  3.     //直接复制小窗口的图像内容
  4.     QPixmap pix = m_scaledPix.copy(m_psDialog->getCutGeometry());
  5.     //将截图内容重命名,并保存到指定目录
  6.     pix.save("D:\\work\\workspace\\qtstudyspace\\PictureEdit\\images\\cut.png", "png");
  7. }
复制代码
回复

使用道具 举报

登录后关闭弹窗

登录参与点评抽奖  加入IT实名职场社区
去登录
快速回复 返回顶部 返回列表