文章目录
- 源码地址,环境:QT5.15,MinGW32位
- 效果演示
- 导入图片
- 设置剪裁区域
- 创建剪裁小窗口
- 重写剪裁小窗口的鼠标事件
- mousePressEvent
- mouseMoveEvent
- mouseReleaseEvent
- 小窗口移动触发父窗口的重绘事件
- 剪裁效果实现
源码地址,环境:QT5.15,MinGW32位
效果演示
导入图片
QPixmap m_srcPix;
QPixmap m_scaledPix;
//从文件导入图片
m_srcPix.load("D:\\Jolly\\A_0voice_chat\\chapter_explanation\\PictureEdit_demo\\PictureEdit\\images\\1.png");
//把导入的图片截取到窗口大小
m_scaledPix = m_srcPix.scaled(ui->label->width(), ui->label->height());
//在窗口显示图片
ui->label->setPixmap(m_scaledPix);
设置剪裁区域
//裁剪头像活动窗口
//设置透明
this->setWindowFlags(Qt::FramelessWindowHint);
//设置矩形区域,整个窗口
this->setGeometry(0, 0, parentWidget()->width(), parentWidget()->height());
CutDialog *m_cutDialog;
//头像剪切窗口
m_cutDialog = new CutDialog(this);
m_cutDialog->show();
创建剪裁小窗口
CutDialog::CutDialog(QWidget *parent) :
QWidget(parent)
{
setGeometry(0,0, 150, 150);
m_mouseDown = false;
}
重写剪裁小窗口的鼠标事件
mousePressEvent
void CutDialog::mousePressEvent(QMouseEvent *event)
{
//获取鼠标按下时的位置
m_startPoint = event->pos();
//判断按下的是否是鼠标左键
m_mouseDown = event->button() == Qt::LeftButton;
}
mouseMoveEvent
要是没有启用鼠标追踪,mouseMoveEvent 只有在鼠标按键被按下并且鼠标移动时才会触发,而且是在mousePressEvent触发之后。
当启用鼠标追踪后,不管鼠标按键是否被按下,只要鼠标移动,mouseMoveEvent就会触发
void CutDialog::mouseMoveEvent(QMouseEvent *event)
{
//获取鼠标移动以后的位置
QPoint dragPoint = event->pos();
if (m_mouseDown) {
//pos保存小部件在其父部件中的位置
QPoint p = QPoint(
//pos() 是对话框在父窗口中的左上角坐标
//dragPoint - m_startPoint 计算鼠标移动的偏移量
//原理: 拖动点相对于对话框的位置保持不变(如从(10,10)点开始拖动,移动后仍抓住该点)
pos().x()+dragPoint.x() - m_startPoint.x(), // 水平方向
pos().y()+dragPoint.y()-m_startPoint.y() // 垂直方向
);
QPoint dragEndge = p;
dragEndge.setX(p.x() + rect().width()); // 对话框右下角X坐标
dragEndge.setY(p.y() + rect().height()); // 对话框右下角Y坐标
//左上角约束,保证小窗口左上角在父窗口范围内
p.setX(p.x() < 0 ? 0 : p.x());
p.setY(p.y() < 0 ? 0 : p.y());
//右下角约束
// 确保右下角X ≤ 父窗口宽度
p.setX(dragEndge.x() > parentWidget()->width()
? parentWidget()->width() - rect().width()
: p.x());
// 确保右下角Y ≤ 父窗口高度
p.setY(dragEndge.y() > parentWidget()->height()
? parentWidget()->height() - rect().height()
: p.y());
//QWidget::move() 对窗口部件的位置进行设置
move(p);
/*
move函数原型
void move(int x, int y);
void move(const QPoint &pos);
*/
}
}
mouseReleaseEvent
释放鼠标时将m_mouseDown 设置为false,避免鼠标右键或其他案件误触发mouseMoveEvent
void CutDialog::mouseReleaseEvent(QMouseEvent *event)
{
m_mouseDown = false;
}
小窗口移动触发父窗口的重绘事件
paintEvent调用时机:
首次显示窗口时
当 PhotoShotDialog 首次显示(例如通过 show() 或 exec())时,系统会自动触发 paintEvent 进行初始绘制。
窗口需要重绘时
窗口被其他窗口遮挡后重新暴露出来
窗口内容发生变化(如子窗口移动、尺寸变化)
调用 update() 或 repaint() 方法强制重绘
子窗口移动时(关键)
当用户拖动 CutDialog时:
CutDialog::mouseMoveEvent() 中调用了 move§ 移动裁剪框
移动操作会自动触发父窗口(PhotoShotDialog)的重绘,因为:
子窗口位置变化导致父窗口的可见区域需要更新
系统自动发送重绘事件到父窗口
void PhotoShotDialog::paintEvent(QPaintEvent *event)
{
QPainterPath painterPath;
QPainterPath p;
p.addRect(x(),y(),this->rect().width(), this->rect().height()); //裁剪头像活动窗口 (蓝色矩形)
//QWidget::geometry()返回一个 QRect 对象。这个对象包含了窗口部件的位置和大小信息
painterPath.addRect(m_cutDialog->geometry()); //头像剪切窗口 (紫色矩形)
QPainterPath drawPath = p.subtracted(painterPath); //subtracted 获取除了painterPath区域以外的窗口
QPainter painter(this);
painter.setOpacity(0.6); //设置Qt控件透明度 0表示全透明,1表示不透明
painter.fillPath(drawPath, QBrush(Qt::black));
}
剪裁效果实现
void PictureEdit::on_pushButton_clicked()
{
//直接复制小窗口的图像内容
QPixmap pix = m_scaledPix.copy(m_psDialog->getCutGeometry());
//将截图内容重命名,并保存到指定目录
pix.save("D:\\work\\workspace\\qtstudyspace\\PictureEdit\\images\\cut.png", "png");
}