基于Qt实现图片查看器

ops/2024/12/22 9:32:58/

一、简介

基于Qt实现的图片查看器。支持如下功能:

  • 图像放大、缩小、拖动
  • 矩形标注框显示,在放大缩小时,标注框的线宽始终保持固定宽度。

二、源码

  1. 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_;
};
  1. 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_;
}

http://www.ppmy.cn/ops/91996.html

相关文章

Java设计模式(适配器模式)

定义 将一个类的接口转换成客户希望的另一个接口。适配器模式让那些接口不兼容的类可以一起工作。 角色 目标抽象类&#xff08;Target&#xff09;&#xff1a;目标抽象类定义客户所需的接口&#xff08;在类适配器中&#xff0c;目标抽象类只能是接口&#xff09;。 适配器类…

Shell脚本-DNS域名解析格式化

Shell脚本-DNS域名解析格式化 大家好&#xff0c;我是秋意零。 今天&#xff0c;分享一个Shell脚本。大家不一定用的上&#xff0c;但可以参考&#xff1b;再一个是可以通过下列需求进行练手&#xff0c;初学者可以试试&#xff01; 脚本还有优化的地方&#xff08;懒得改了…

【Android】ContentProvider基本概念

ContentProvider Android权限机制详解 <manifest xmlns:android"http://schemas.android.com/apk/res/android"package"com.example.broadcasttest"> <uses-permission android:name"android.permission.RECEIVE_BOOT_COMPLETED" />…

计算机网络408考研 2014

1 计算机网络408考研2014年真题解析_哔哩哔哩_bilibili 1 111 1 11

Python | Leetcode Python题解之第326题3的幂

题目&#xff1a; 题解&#xff1a; class Solution:def isPowerOfThree(self, n: int) -> bool:return n > 0 and 1162261467 % n 0

SpringMVC学习笔记---带你快速入门和复习

一、初识SpringMVC 1.1、什么是SpringMVC 1.1.1、什么是MVC MVC是一种软件架构模式&#xff08;是一种软件架构设计思想&#xff0c;不止Java开发中用到&#xff0c;其它语言也需要用到&#xff09;&#xff0c;它将应用分为三块&#xff1a; M&#xff1a;Model&#xff0…

牛客周赛 Round 54

清楚姐姐的糖葫芦 思路&#xff1a;模拟 void solve() {string s; cin >> s;int ans 0;for (auto i : s) ans (i o);cout << ans << \n; }清楚姐姐买竹鼠 思路&#xff1a;全买 b b b&#xff0c;全买 a a a和混合买的取最小值 void solve() {int a, …

51单片机个人学习笔记16(红外遥控)

前言 本篇文章属于STC89C52单片机&#xff08;以下简称单片机&#xff09;的学习笔记&#xff0c;来源于B站教学视频。下面是这位up主的视频链接。本文为个人学习笔记&#xff0c;只能做参考&#xff0c;细节方面建议观看视频&#xff0c;肯定受益匪浅。 [1-1] 课程简介_哔哩…