#include "Zoom.h"
Zoom::Zoom(QWidget* parent) : QWidget(parent) {
// 基础设置
setWindowTitle("Zoom Tool");
resize(600, 600);
setStyleSheet("background-color: white;");
// 初始化组件,构建一个可以查看和操作图片的界面
scrollArea = new QScrollArea(this);
imageLabel = new QLabel(scrollArea);
imageLabel->setAlignment(Qt::AlignCenter);
imageLabel->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored);
scrollArea->setWidget(imageLabel);
scrollArea->setBackgroundRole(QPalette::Dark);
// ===== 添加事件过滤器 =====
scrollArea->viewport()->installEventFilter(this);
// 布局
QVBoxLayout* mainLayout = new QVBoxLayout(this);
mainLayout->addWidget(scrollArea);
// 按钮区域
QHBoxLayout* buttonLayout = new QHBoxLayout();
QPushButton* prevBtn = new QPushButton("前一张");
QPushButton* openBtn = new QPushButton("打开图片");
QPushButton* nextBtn = new QPushButton("后一张");
QPushButton* resetBtn = new QPushButton("恢复");
buttonLayout->addWidget(prevBtn);
buttonLayout->addWidget(openBtn);
buttonLayout->addWidget(nextBtn);
buttonLayout->addWidget(resetBtn);
mainLayout->addLayout(buttonLayout);
// 坐标显示
QHBoxLayout* coordLayout = new QHBoxLayout();
coordXLabel = new QLabel("X坐标:0");
coordYLabel = new QLabel("Y坐标:0");
// grayLabel = new QLabel("灰度值:0");
coordLayout->addWidget(coordXLabel);
coordLayout->addWidget(coordYLabel);
//coordLayout->addWidget(grayLabel);
mainLayout->addLayout(coordLayout);
// 缩放比例标签,右上角的显示缩放比
scaleLabel = new QLabel(this);
scaleLabel->setStyleSheet("background-color: rgba(255,255,255,150);");
scaleLabel->setAlignment(Qt::AlignLeft | Qt::AlignTop);
scaleLabel->setFixedSize(100, 30);
scaleLabel->hide(); // 初始时隐藏,只有在缩放操作时才显示
// 连接信号槽
connect(openBtn, &QPushButton::clicked, this, &Zoom::openImage);
connect(resetBtn, &QPushButton::clicked, this, &Zoom::resetImage);
connect(prevBtn, &QPushButton::clicked, this, &Zoom::prevImage);
connect(nextBtn, &QPushButton::clicked, this, &Zoom::nextImage);
// 定时器
scaleTimer = new QTimer(this);
scaleTimer->setSingleShot(true);
//接定时器的timeout信号到一个lambda函数,当定时器超时时,执行scaleLabel->hide()隐藏标签
connect(scaleTimer, &QTimer::timeout, this, [this]() {
scaleLabel->hide();
});
scaleFactor = 1.0;
}
//实现图片缩放功能
void Zoom::wheelEvent(QWheelEvent* event) {
if (image.isNull()) {
event->ignore();
return;
}
// 1. 获取鼠标在视口中的位置(相对于 scrollArea 视口)
QPointF mousePos = event->position();
// 2. 计算鼠标在图像中的位置(考虑当前滚动位置和缩放比例)
QPointF imagePosBefore = QPointF(
(mousePos.x() + scrollArea->horizontalScrollBar()->value()) / scaleFactor,
(mousePos.y() + scrollArea->verticalScrollBar()->value()) / scaleFactor
);
// 3. 计算缩放因子
const double ZOOM_RATIO = 1.1;
double angle = event->angleDelta().y();
if (angle == 0) return;
double factor = (angle > 0) ? ZOOM_RATIO : (1.0 / ZOOM_RATIO);
double newScale = qBound(0.1, scaleFactor * factor, 10.0);
if (qFuzzyCompare(newScale, scaleFactor)) {
event->accept();
return;
}
// 4. 应用新缩放比例
QPixmap scaledPixmap = QPixmap::fromImage(
image.scaled(image.size() * newScale,
Qt::KeepAspectRatio,
Qt::SmoothTransformation));
imageLabel->setPixmap(scaledPixmap);
imageLabel->resize(scaledPixmap.size());
// 5. 计算新的滚动位置(保持鼠标下的图像点不变)
QPointF imagePosAfter = imagePosBefore * newScale;
QPoint newScrollPos(
qRound(imagePosAfter.x() - mousePos.x()),
qRound(imagePosAfter.y() - mousePos.y())
);
// 限制滚动范围
newScrollPos.setX(qMax(0, qMin(imageLabel->width() - scrollArea->viewport()->width(), newScrollPos.x())));
newScrollPos.setY(qMax(0, qMin(imageLabel->height() - scrollArea->viewport()->height(), newScrollPos.y())));
scrollArea->horizontalScrollBar()->setValue(newScrollPos.x());
scrollArea->verticalScrollBar()->setValue(newScrollPos.y());
// 6. 更新缩放比例和UI
scaleFactor = newScale;
scaleLabel->setText(QString("缩放: %1%").arg(qRound(scaleFactor * 100)));
scaleLabel->move(10, 10);
scaleLabel->show();
scaleTimer->start(5000);
event->accept();
}
//void Zoom::updateCursorState() {
// if (!imageLabel->pixmap().isNull() &&
// (imageLabel->pixmap().width() > scrollArea->viewport()->width() ||
// imageLabel->pixmap().height() > scrollArea->viewport()->height())) {
// setCursor(Qt::OpenHandCursor);
// } else {
// setCursor(Qt::ArrowCursor);
// }
//}
bool Zoom::eventFilter(QObject* obj, QEvent* event) {
if (obj == scrollArea->viewport() && event->type() == QEvent::Wheel) {
// 如果事件发生在视口上,直接调用wheelEvent
wheelEvent(static_cast<QWheelEvent*>(event));
return true; // 事件已处理
}
return QWidget::eventFilter(obj, event);
}
//鼠标按下事件
void Zoom::mousePressEvent(QMouseEvent* event) {
if (event->button() == Qt::LeftButton && !image.isNull()) {
// 只要图片存在就允许拖动
dragPos = event->pos();
setCursor(Qt::ClosedHandCursor);
}
else if (event->button() == Qt::RightButton && !image.isNull()) {
// 右键坐标显示
QPoint imagePos = imageLabel->mapFrom(this, event->pos());
if (imageLabel->rect().contains(imagePos)) {
QPoint pixelPos = imagePos / scaleFactor;
coordXLabel->setText(QString("X坐标:%1").arg(pixelPos.x()));
coordYLabel->setText(QString("Y坐标:%1").arg(pixelPos.y()));
/* if (image.format() == QImage::Format_RGB32 ||
image.format() == QImage::Format_ARGB32) {
QRgb pixel = image.pixel(pixelPos);
int gray = qGray(pixel);
grayLabel->setText(QString("灰度值:%1").arg(gray));
}*/
}
}
}
//鼠标移动事件
void Zoom::mouseMoveEvent(QMouseEvent* event) {
if ((event->buttons() & Qt::LeftButton) && !dragPos.isNull()) {
QPoint delta = dragPos - event->pos();
dragPos = event->pos();
// 直接应用拖动,不检查边界
scrollArea->horizontalScrollBar()->setValue(
scrollArea->horizontalScrollBar()->value() + delta.x());
scrollArea->verticalScrollBar()->setValue(
scrollArea->verticalScrollBar()->value() + delta.y());
}
}
//鼠标释放事件
void Zoom::mouseReleaseEvent(QMouseEvent* event) {
if (event->button() == Qt::LeftButton) {
dragPos = QPoint();
// 只要图片存在就显示张开的手型光标
if (!image.isNull()) {
setCursor(Qt::OpenHandCursor);
}
else {
setCursor(Qt::ArrowCursor);
}
}
}
//打开图片文件
void Zoom::openImage() {
QString fileName = QFileDialog::getOpenFileName(this, "打开图片", currentFolder,
"Images (*.png *.jpg *.bmp)");
if (!fileName.isEmpty()) {
// 获取文件夹路径和该文件夹下所有图片
QFileInfo fileInfo(fileName);
currentFolder = fileInfo.path();
QDir dir(currentFolder);
QStringList filters = { "*.png", "*.jpg", "*.bmp" };
imagePaths = dir.entryList(filters, QDir::Files, QDir::Name);
// 设置当前图片索引
currentImageIndex = imagePaths.indexOf(fileInfo.fileName());
// 加载图片
loadCurrentImage();
}
}
// 加载当前图片
void Zoom::loadCurrentImage() {
if (currentImageIndex >= 0 && currentImageIndex < imagePaths.size()) {
QString imagePath = currentFolder + "/" + imagePaths[currentImageIndex];
image.load(imagePath);
if (image.isNull()) {
QMessageBox::warning(this, "错误", "无法加载图片");
return;
}
scaleFactor = 1.0;
imageLabel->setPixmap(QPixmap::fromImage(image));
imageLabel->adjustSize();
imageLabel->setAlignment(Qt::AlignCenter);
setWindowTitle("Zoom Tool - " + imagePaths[currentImageIndex]);
// 只在加载和切换图片时调用居中显示和自适应缩小
adjustAndCenterImage();
if (!image.isNull()) {
setCursor(Qt::OpenHandCursor);
}
}
}
//重置图片显示
void Zoom::resetImage() {
if (image.isNull()) return;
scaleFactor = 1.0;
imageLabel->setPixmap(QPixmap::fromImage(image));
imageLabel->adjustSize();
imageLabel->setAlignment(Qt::AlignCenter);
// 只在恢复时调用居中显示和自适应缩小
adjustAndCenterImage();
if (!image.isNull()) {
setCursor(Qt::OpenHandCursor);
}
else {
setCursor(Qt::ArrowCursor);
}
scaleLabel->hide();
}
void Zoom::adjustAndCenterImage() {
if (image.isNull()) return;
// 获取视图和图像尺寸
QSize viewSize = scrollArea->viewport()->size();
QSize imageSize = image.size();
// 计算适合的缩放比例
double widthRatio = (double)viewSize.width() / imageSize.width();
double heightRatio = (double)viewSize.height() / imageSize.height();
scaleFactor = qMin(widthRatio, heightRatio);
// 如果图像小于视图,保持原始大小
if (imageSize.width() < viewSize.width() && imageSize.height() < viewSize.height()) {
scaleFactor = 1.0;
}
// 应用缩放
QPixmap scaledPixmap = QPixmap::fromImage(
image.scaled(image.size() * scaleFactor,
Qt::KeepAspectRatio,
Qt::SmoothTransformation));
imageLabel->setPixmap(scaledPixmap);
imageLabel->resize(scaledPixmap.size());
imageLabel->setAlignment(Qt::AlignCenter);
// 强制重新计算布局
scrollArea->widget()->setContentsMargins(0, 0, 0, 0);
scrollArea->setAlignment(Qt::AlignCenter);
// 计算居中位置(考虑滚动区域的实际可用空间)
int hMax = qMax(0, imageLabel->width() - viewSize.width());
int vMax = qMax(0, imageLabel->height() - viewSize.height());
// 设置滚动条位置(强制居中)
scrollArea->horizontalScrollBar()->setRange(0, hMax);
scrollArea->verticalScrollBar()->setRange(0, vMax);
scrollArea->horizontalScrollBar()->setValue(hMax / 2);
scrollArea->verticalScrollBar()->setValue(vMax / 2);
// 显示缩放比例
scaleLabel->setText(QString("缩放: %1%").arg(qRound(scaleFactor * 100)));
scaleLabel->move(10, 10);
scaleLabel->show();
scaleTimer->start(5000);
}
// 调整图像显示
//void Zoom::adjustImageToView() {
// if (image.isNull()) return;
//
// // 获取视图和图像尺寸
// QSize viewSize = scrollArea->viewport()->size();
// QSize imageSize = image.size();
//
// // 计算适合的缩放比例
// double widthRatio = (double)viewSize.width() / imageSize.width();
// double heightRatio = (double)viewSize.height() / imageSize.height();
// scaleFactor = qMin(widthRatio, heightRatio);
//
// // 如果图像小于视图,保持原始大小
// if (imageSize.width() < viewSize.width() && imageSize.height() < viewSize.height()) {
// scaleFactor = 1.0;
// }
//
// // 应用缩放
// QPixmap scaledPixmap = QPixmap::fromImage(
// image.scaled(image.size() * scaleFactor,
// Qt::KeepAspectRatio,
// Qt::SmoothTransformation));
//
// imageLabel->setPixmap(scaledPixmap);
// imageLabel->resize(scaledPixmap.size());
// imageLabel->setAlignment(Qt::AlignCenter);
//
// // 强制重新计算布局
// scrollArea->widget()->setContentsMargins(0, 0, 0, 0);
// scrollArea->setAlignment(Qt::AlignCenter);
//
// // 显示缩放比例
// scaleLabel->setText(QString("缩放: %1%").arg(qRound(scaleFactor * 100)));
// scaleLabel->move(10, 10);
// scaleLabel->show();
// scaleTimer->start(5000);
//}
// 添加前一张图片功能
void Zoom::prevImage() {
if (imagePaths.isEmpty()) {
QMessageBox::information(this, "提示", "请先打开图片");
return;
}
currentImageIndex--;
if (currentImageIndex < 0) {
currentImageIndex = imagePaths.size() - 1; // 循环到最后一张
}
loadCurrentImage();
}
// 添加后一张图片功能
void Zoom::nextImage() {
if (imagePaths.isEmpty()) {
QMessageBox::information(this, "提示", "请先打开图片");
return;
}
currentImageIndex++;
if (currentImageIndex >= imagePaths.size()) {
currentImageIndex = 0; // 循环到第一张
}
loadCurrentImage();
}
以上代码,怎么修改为以鼠标光标为中心点进行缩放,就是在缩放操作时,图像位置,以鼠标所在点为中心,即鼠标所在的图像上那一点,在视窗里保持位置不变,来进行缩放
最新发布