实现在QLabel显示的影像上画图形,并和影像同步放大缩小
关于影像在QLabel的显示,如何随鼠标滚轮实现放大缩小,可以参考我的上一篇博客
QT学习笔记(三)——vs2019+Qt实现打开影像并以鼠标为中心用滚轮控制图片缩放
本篇博客接着这个继续实现如何在QLabel打开的图像上画一个形状(以矩形为例),并且能让这个图形和影像一起随鼠标滚轮放大缩小。
1.首先新建一个myLabel类,重写myLabel的paintEvent方法。
这个方法的目的是保证你能在这个myLabel类生成的对象中画图并显示
//myLabel.h
#include <qlabel.h>
#include <QPainter>
#include <QPoint>
#include <QColor>
#include <QPen>
#include <QDebug>
class myLabel :
public QLabel
{
Q_OBJECT
public:
myLabel(QWidget* parent = nullptr);
//~myLabel();
//重写绘制事件
virtual void paintEvent(QPaintEvent* event) override;
void DrawRangle(int x, int y, int w, int h);
int x;
int y;
int w;
int h;
};
//myLabel.cpp
#include "myLabel.h"
myLabel::myLabel(QWidget *parent):QLabel(parent) {}
void myLabel::DrawRangle(int xx, int yy, int hh, int ww)
{
x = xx;
y = yy;
w = ww;
h = hh;
update();
}
//重写绘制事件
void myLabel::paintEvent(QPaintEvent* event)
{
QLabel::paintEvent(event);//必须有,才能让背景图片显示出来
QPainter painter(this);
QPen pen;
pen.setColor(Qt::blue);
pen.setWidth(5);
painter.setPen(pen);
painter.drawRect(QRect(x, y, w, h));
painter.end();
}
2.然后在tstQt中将myLabel.h头文件包含进去,并加入新的成员变量(矩形框)
并在tstQt类中将之前定义的imgLabel的变量类型从QLabel改为自己定义的myLabel,即在tstQt.h中
myLabel* imgLabel;//图像显示框
//加入新的成员变量
QPoint onept;//矩形左上角点在影像中的坐标
int w;//矩形宽度
int h;
同时,在tstQt.cpp中的InitImage()函数中,将imgLabel的初始化修改为:
imgLabel = new myLabel(dock_Image);
并在该函数末尾添加:
w = 50;
h = 50;
onept.setX(50);
onept.setY(50);
imgLabel->DrawRangle(onept.x(), onept.y(), w,h);
这时候运行,就可以看到多了一个蓝色的矩形框了,但是这个矩形相对于label的左上角点的固定的,当鼠标放缩影像时,矩形框不会跟随放缩。因此需要修改wheelevent()函数,下面直接放上该函数的完整代码:
void tstQt::wheelEvent(QWheelEvent* event)
{
int dockWin_pos = scrollArea->geometry().y()+dock_Image->geometry().y();
int pp = scrollArea->pos().y();
QPoint pt = onept;//要画的矩形左上角点
QScrollBar* tmph = scrollArea->horizontalScrollBar();
QScrollBar* tmpv = scrollArea->verticalScrollBar();
QPoint pos = event->pos();//得到当前鼠标在窗口的位置
QRect tmplab = imgLabel->geometry();//获得imglabel的位置
int th = pos.x() - tmplab.x();
int tv = pos.y() - tmplab.y() - dockWin_pos;//缩放前鼠标点在label中的坐标,这里的79是窗体标题的高度
imgLabel->setPixmap(QPixmap::fromImage(m_image)); // 这一句是为了防止自适应窗口之后进行放缩图像分辨率变低,所以label重新加载原始影像
double ratio = (double)m_image.height() / (double)m_image.width();//图像的比例
QPoint numDegrees; // 定义指针类型参数numDegrees用于获取滚轮转角
numDegrees = event->angleDelta(); // 获取滚轮转角
int step = 0; // 设置中间参数step用于将获取的数值转换成整数型
if (!numDegrees.isNull()) // 判断滚轮是否转动
{
step = numDegrees.y(); // 将滚轮转动数值传给中间参数step
}
event->accept(); // 获取事件
int currentWidth = imgLabel->width(); // 获取当前图像的宽
int currentHeight = imgLabel->height(); // 获取当前图像的高
double stepr = (double)(step) / (double)(currentWidth); // (1.0+stepr)为放缩比例=r
currentWidth += step; // 对当前图像的高累加
currentHeight += (int)(step*ratio+0.5); // 对当前图像的宽累加(四舍五入)
double r = (double)currentWidth / (double)m_image.width();//始终计算相对于原影像的放缩比例,用来计算所画点放缩后的坐标
int x = onept.x() * r+0.5;
int y = onept.y() * r + 0.5;
int wtmp = w * r ;
int htmp = h * r ;
if (step > 0) // 判断图像是放大还是缩小
{
QString imgsize = QString("图像放大,尺寸为:%1 * %2")
.arg(currentWidth).arg(currentHeight);
qDebug() << imgsize; // 打印放大后的图像尺寸
}
else
{
QString imgsize = QString("图像缩小,尺寸为:%1 * %2")
.arg(currentWidth).arg(currentHeight);
qDebug() << imgsize; // 打印缩小后的图像尺寸
}
imgLabel->resize(currentWidth, currentHeight); // 通过更新图像显示控件的大小来更新图像大小
int move_x = stepr * th + 0.5;
int move_y = stepr * tv + 0.5;
tmph->setValue(tmph->value()+ move_x);
tmpv->setValue(tmpv->value() + move_y);
//对于矩形进行刷新
//imgLabel->DrawRangle(100, 100, 20, 10);
imgLabel->DrawRangle(x,y,wtmp,htmp);
}
其实主要就是添加了计算每次刷新时矩形左上角点的坐标,以及新的长宽,每次update()时,会清除上一次画的,所以放缩前的矩形刷新后就不会存在了。运行效果:
打开影像:
放大:
缩小:
放大缩小时,该矩形在图片上的位置是不变的。
3.还有自适应窗口的函数autosize()也要做相应修改
void tstQt::autoSize() // 自适应窗口
{
imgLabel->setPixmap(QPixmap::fromImage(m_image));
imgLabel->resize(m_image.width(), m_image.height());
QImage Img;
double ImgRatio = 1.0 * imgLabel->pixmap()->toImage().width() / imgLabel->pixmap()->toImage().height(); // 图像宽高比
double WinRatio = 1.0 * (scrollArea->width() - 2) / (scrollArea->height() - 2); // 窗口宽高比
if (ImgRatio > WinRatio) // 图像宽高比大于图像宽高比
{
Img = imgLabel->pixmap()->toImage().scaled((scrollArea->width() - 2), (scrollArea->width() - 2) / ImgRatio, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
}
else // 图像宽高比小于等于图像宽高比
{
Img = imgLabel->pixmap()->toImage().scaled((scrollArea->height() - 2) * ImgRatio, (scrollArea->height() - 2), Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
}
imgLabel->setPixmap(QPixmap::fromImage(Img)); // 显示图像
imgLabel->resize(Img.width(), Img.height());
double r = (double)Img.width() / (double)m_image.width();
int x = onept.x() * r + 0.5;
int y = onept.y() * r + 0.5;
int wtmp = w * r;
int htmp = h * r;
imgLabel->DrawRangle(x, y, wtmp, htmp);
}