一、简介
基于Qt实现的图片查看器。支持如下功能:
- 图像放大、缩小、拖动
- 矩形标注框显示,在放大缩小时,标注框的线宽始终保持固定宽度。
二、源码
- ImgViewWidget.hpp
// ImgViewWidget.hpp
#pragma once
#include <QImage>
#include <QPixmap>
#include <QWidget>class ImgViewWidget final : public QWidget {Q_OBJECT
public:// 标注框(矩形区域和描述文字)using MarkBox = QPair<QRect, QString>;explicit ImgViewWidget(QWidget* parent = nullptr);~ImgViewWidget() override = default;// 设置图像void set_image(const QImage& img);void set_pixmap(const QPixmap& img);// 复位图像(复位缩放和移动)void reset_transform();// 清除图像void clear();// 设置缩放是否启用(默认启用)void set_zoom_enable(bool enable);// 设置标注框显示(默认显示)void set_mark_visible(bool visible);// 设置标注框颜色,默认红色void set_mark_color(const QColor& color);// 设置标注框void set_mark_box(const QVector<MarkBox>& marks);[[nodiscard]] QPixmap original_pix() const;[[nodiscard]] bool zoom_enable() const;[[nodiscard]] bool mark_visible() const;[[nodiscard]] QColor mark_color() const;[[nodiscard]] const QVector<MarkBox>& mark_box() const;protected:void paintEvent(QPaintEvent* event) override;void wheelEvent(QWheelEvent* event) override;void mousePressEvent(QMouseEvent* event) override;void mouseMoveEvent(QMouseEvent* event) override;void mouseReleaseEvent(QMouseEvent* event) override;void resizeEvent(QResizeEvent* event) override;private:QPixmap original_pix_;QPixmap display_pix_;QPointF prev_point_;QPointF move_step_;float zoom_scale_;bool move_start_;bool zoom_enable_;bool mark_visible_;QColor mark_color_;QVector<MarkBox> marks_;
};
- ImgViewWidget.cpp
// ImgViewWidget.cpp
#include "ImgViewWidget.hpp"#include <QPainter>
#include <QWheelEvent>ImgViewWidget::ImgViewWidget(QWidget* parent): QWidget(parent), zoom_scale_{1.0F}, move_start_{}, zoom_enable_{true}, mark_visible_{true}, mark_color_{Qt::red} {setWindowTitle(tr("Image View"));
}void ImgViewWidget::set_image(const QImage& img) {set_pixmap(QPixmap::fromImage(img));
}void ImgViewWidget::set_pixmap(const QPixmap& img) {original_pix_ = img;display_pix_ = original_pix_.scaled(zoom_scale_ * size(), Qt::KeepAspectRatio);update();
}void ImgViewWidget::reset_transform() {zoom_scale_ = 1.0f;move_step_ = QPoint(0, 0);display_pix_ = original_pix_.scaled(zoom_scale_ * size(), Qt::KeepAspectRatio);update();
}void ImgViewWidget::clear() {set_pixmap(QPixmap{});
}QPixmap ImgViewWidget::original_pix() const {return original_pix_;
}void ImgViewWidget::set_zoom_enable(bool enable) {zoom_enable_ = enable;
}void ImgViewWidget::paintEvent(QPaintEvent* event) {QPainter painter(this);const QPoint top_left(move_step_.x() + (width() - display_pix_.width()) / 2, move_step_.y() + (height() - display_pix_.height()) / 2);painter.drawPixmap(top_left, display_pix_);if (!mark_visible_) {return;}const float factor = static_cast<float>(display_pix_.width()) / static_cast<float>(original_pix_.width());for (const auto& [box, label] : marks_) {const QRect adjust_box(top_left.x() + box.x() * factor, top_left.y() + box.y() * factor, box.width() * factor,box.height() * factor);painter.setPen(QPen(mark_color_, 1));painter.drawRect(adjust_box);painter.drawText(adjust_box.x(), adjust_box.y() - 2, label);}
}void ImgViewWidget::wheelEvent(QWheelEvent* event) {if (!zoom_enable_) {return;}if (event->angleDelta().y() > 0) {zoom_scale_ *= 1.1;} else {zoom_scale_ *= 0.9;}display_pix_ = original_pix_.scaled(zoom_scale_ * size(), Qt::KeepAspectRatio);update();
}void ImgViewWidget::mousePressEvent(QMouseEvent* event) {if (!zoom_enable_) {event->ignore();return;}if (event->button() == Qt::LeftButton) {if (!move_start_) {move_start_ = true;prev_point_ = event->globalPosition();}} else if (event->button() == Qt::RightButton) {reset_transform();}
}void ImgViewWidget::mouseMoveEvent(QMouseEvent* event) {if (!zoom_enable_) {event->ignore();return;}if (move_start_) {const QPointF point = event->globalPosition();move_step_ += point - prev_point_;prev_point_ = point;update();}
}void ImgViewWidget::mouseReleaseEvent(QMouseEvent* event) {if (!zoom_enable_) {event->ignore();return;}if (event->button() == Qt::LeftButton) {move_start_ = false;}
}void ImgViewWidget::resizeEvent(QResizeEvent* event) {if (!original_pix_.isNull()) {display_pix_ = original_pix_.scaled(zoom_scale_ * size(), Qt::KeepAspectRatio);}update();
}void ImgViewWidget::set_mark_visible(bool visible) {mark_visible_ = visible;update();
}void ImgViewWidget::set_mark_color(const QColor& color) {mark_color_ = color;update();
}void ImgViewWidget::set_mark_box(const QVector<ImgViewWidget::MarkBox>& marks) {marks_ = marks;update();
}bool ImgViewWidget::zoom_enable() const {return zoom_enable_;
}bool ImgViewWidget::mark_visible() const {return mark_visible_;
}QColor ImgViewWidget::mark_color() const {return mark_color_;
}const QVector<ImgViewWidget::MarkBox>& ImgViewWidget::mark_box() const {return marks_;
}