15、Qt显示图片并支持缩放、移动等操作

news2024/12/26 20:55:37

一、新建项目

点击“New Project”,选择“Application”“Qt Widget Application”,点击“Choose”

更改项目名称和位置

选择编译器

默认

默认

二、创建自定义类

右击项目名,选择“Add New”

选择“C++” -> "C++ Class",点击“Choose”

更改名称和基类

默认

更改photolabel.h的代码

#ifndef PHOTOLABEL_H
#define PHOTOLABEL_H

#include <QObject>
#include <QLabel>
#include <QMenu>

class PhotoLabel : public QLabel
{
public:
    explicit PhotoLabel(QWidget *parent = nullptr);

    void setPhoto(QString);  //设置图片

    void clearShow();   //清空显示

protected:
    void contextMenuEvent(QContextMenuEvent *event) override;   //右键菜单
    void paintEvent(QPaintEvent *event);                        //QPaint画图
    void wheelEvent(QWheelEvent *event) override;               //鼠标滚轮滚动
    void mousePressEvent(QMouseEvent *event) override;          //鼠标摁下
    void mouseMoveEvent(QMouseEvent *event) override;           //鼠标松开
    void mouseReleaseEvent(QMouseEvent *event) override;        //鼠标发射事件

private slots:
    void initWidget();      //初始化
    void onSelectImage();   //选择打开图片
    void onZoomInImage();   //图片放大
    void onZoomOutImage();  //图片缩小
    void onPresetImage();   //图片还原

private:
    QImage m_image;           //显示的图片
    qreal m_zoomValue = 1.0;  //鼠标缩放值
    int m_xPtInterval = 0;    //平移X轴的值
    int m_yPtInterval = 0;    //平移Y轴的值
    QPoint m_oldPos;          //旧的鼠标位置
    bool m_pressed = false;   //鼠标是否被摁压
    QString m_localFileName;  //文件名称
    QMenu *m_menu;            //右键菜单
};

#endif // PHOTOLABEL_H

更改photolabel.cpp的代码

#include "photolabel.h"
#include <QPainter>
#include <QDebug>
#include <QWheelEvent>
#include <QFileDialog>

PhotoLabel::PhotoLabel(QWidget *parent):QLabel(parent)
{
    initWidget();
}

/**
* @brief PhotoLabel::initWidget 初始化
*/
void PhotoLabel::initWidget()
{
    //初始化右键菜单
    m_menu = new QMenu(this);
    QAction *loadImage = new QAction;
    loadImage->setText("选择图片");
    connect(loadImage, &QAction::triggered, this, &PhotoLabel::onSelectImage);
    m_menu->addAction(loadImage);
    m_menu->addSeparator();

    QAction *zoomInAction = new QAction;
    zoomInAction->setText("放大");
    connect(zoomInAction, &QAction::triggered, this, &PhotoLabel::onZoomInImage);
    m_menu->addAction(zoomInAction);

    QAction *zoomOutAction = new QAction;
    zoomOutAction->setText("缩小");
    connect(zoomOutAction, &QAction::triggered, this, &PhotoLabel::onZoomOutImage);
    m_menu->addAction(zoomOutAction);

    QAction *presetAction = new QAction;
    presetAction->setText("还原");
    connect(presetAction, &QAction::triggered, this, &PhotoLabel::onPresetImage);
    m_menu->addAction(presetAction);
    m_menu->addSeparator();

    QAction *clearAction = new QAction;
    clearAction->setText("清空");
    connect(clearAction, &QAction::triggered, this, &PhotoLabel::clearShow);
    m_menu->addAction(clearAction);
}

/**
* @brief PhotoLabel::setPhoto 设置要显示的图片
* @param path 图片路径
*/
void PhotoLabel::setPhoto(QString path)
{
    if(path.isEmpty())
    {
        return;
    }

    m_zoomValue = 1.0;
    m_xPtInterval = 0;
    m_yPtInterval = 0;

    m_localFileName = path;
    m_image.load(m_localFileName);
    update();
}

/**
* @brief PhotoLabel::clearShow 清空
*/
void PhotoLabel::clearShow()
{
    m_localFileName = "";
    m_image = QImage();
    this->clear();
}

/**
* @brief PhotoLabel::paintEvent 绘图事件
* @param event
*/
void PhotoLabel::paintEvent(QPaintEvent *event)
{
    if(m_image.isNull())
        return QWidget::paintEvent(event);

    QPainter painter(this);

    // 根据窗口计算应该显示的图片的大小
    int width = qMin(m_image.width(), this->width());
    int height = int(width * 1.0 / (m_image.width() * 1.0 / m_image.height()));
    height = qMin(height, this->height());
    width = int(height * 1.0 * (m_image.width() * 1.0 / m_image.height()));

    // 平移
    painter.translate(this->width() / 2 + m_xPtInterval, this->height() / 2 + m_yPtInterval);

    // 缩放
    painter.scale(m_zoomValue, m_zoomValue);

    // 绘制图像
    QRect picRect(-width / 2, -height / 2, width, height);
    painter.drawImage(picRect, m_image);

    QWidget::paintEvent(event);
}

/**
* @brief PhotoLabel::wheelEvent 滚轮滚动缩放图片
* @param event
*/
void PhotoLabel::wheelEvent(QWheelEvent *event)
{
    int value = event->delta();
    if (value > 0)  //放大
        onZoomInImage();
    else            //缩小
        onZoomOutImage();

    update();
}

/**
* @brief PhotoLabel::mousePressEvent 鼠标按下,为移动图片做准备
* @param event
*/
void PhotoLabel::mousePressEvent(QMouseEvent *event)
{
    m_oldPos = event->pos();
    m_pressed = true;
    this->setCursor(Qt::ClosedHandCursor); //设置鼠标样式
}

/**
* @brief PhotoLabel::mouseMoveEvent 鼠标按下后,再移动鼠标,图片随之移动
* @param event
*/
void PhotoLabel::mouseMoveEvent(QMouseEvent *event)
{
    if (!m_pressed)
        return QWidget::mouseMoveEvent(event);

    QPoint pos = event->pos();
    int xPtInterval = pos.x() - m_oldPos.x();
    int yPtInterval = pos.y() - m_oldPos.y();

    m_xPtInterval += xPtInterval;
    m_yPtInterval += yPtInterval;

    m_oldPos = pos;
    update();
}

/**
* @brief PhotoLabel::mouseReleaseEvent 鼠标抬起,图片移动结束
*/
void PhotoLabel::mouseReleaseEvent(QMouseEvent */*event*/)
{
    m_pressed = false;
    this->setCursor(Qt::ArrowCursor); //设置鼠标样式
}

/**
* @brief PhotoLabel::contextMenuEvent 右键显示菜单栏
* @param event
*/
void PhotoLabel::contextMenuEvent(QContextMenuEvent *event)
{
    QPoint pos = event->pos();
    pos = this->mapToGlobal(pos);
    m_menu->exec(pos);
}

/**
* @brief PhotoLabel::onSelectImage 选择图片
*/
void PhotoLabel::onSelectImage()
{
    QString path = QFileDialog::getOpenFileName(this, "选择 要显示的图片", "./", tr("Images (*.png *.jpg *.jpeg)"));
    if (path.isEmpty())
        return;

    setPhoto(path);
}

/**
* @brief PhotoLabel::onZoomInImage 图片放大
*/
void PhotoLabel::onZoomInImage()
{
    m_zoomValue += 0.05;
    update();
}

/**
* @brief PhotoLabel::onZoomOutImage 图片缩小
*/
void PhotoLabel::onZoomOutImage()
{
    m_zoomValue -= 0.05;
    if (m_zoomValue <= 0)
    {
        m_zoomValue = 0.05;
        return;
    }

    update();
}

/**
* @brief PhotoLabel::onPresetImage 图片还原
*/
void PhotoLabel::onPresetImage()
{
    m_zoomValue = 1.0;
    m_xPtInterval = 0;
    m_yPtInterval = 0;
    update();
}

三、自定义类的使用

双击“mainwindow.ui”

拖拽一个Label,并进行网格布局

右击TextLabel,选择“提升为”

 输入类名称,点击“添加”

点击“提升” 

label的基类被更改

四、运行测试

右击界面,选择“选择图片”

添加一张图片之后,可以右击选择“放大/缩小/还原”等,也可以鼠标滚轮控制缩放;

也可以鼠标点击不松开,移动鼠标,从而使图片移

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1327817.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

数据结构和算法-二叉排序树(定义 查找 插入 删除 时间复杂度)

文章目录 二叉排序树总览二叉排序树的定义二叉排序树的查找二叉排序树的插入二叉排序树的构造二叉排序树的删除删除的是叶子节点删除的是只有左子树或者只有右子树的节点删除的是有左子树和右子树的节点 查找效率分析查找成功查找失败 小结 二叉排序树 总览 二叉排序树的定义 …

7-1 建立二叉搜索树并查找父结点(PTA - 数据结构)

按输入顺序建立二叉搜索树&#xff0c;并搜索某一结点&#xff0c;输出其父结点。 输入格式: 输入有三行&#xff1a; 第一行是n值&#xff0c;表示有n个结点&#xff1b; 第二行有n个整数&#xff0c;分别代表n个结点的数据值&#xff1b; 第三行是x&#xff0c;表示要搜索值…

华清远见作业第十四天

思维导图 1、顺序表按元素删除 代码&#xff1a; int delete_num_delete(sqlist *list,datatype key) {int indexseek_num(list,key);//元素查找函数if(index-1){return -1;}delete_index(list,index);return 0; } 2、顺序表按照元素修改 代码&#xff1a; //顺序表按照元…

人流量监测识别摄像机

人流量监测识别摄像机是一种基于人工智能技术的智能监控设备&#xff0c;其主要功能是通过摄像头捕捉实时画面&#xff0c;利用深度学习算法对画面中的人数进行实时识别和统计。这种摄像机可以广泛应用于各种场合&#xff0c;如商场、车站、学校、医院等公共场所&#xff0c;以…

Transformer引领AI领域:从模型到平台,全方位探索与实践

编辑推荐 在不到4 年的时间里&#xff0c;Transformer 模型以其强大的性能和创新的思想&#xff0c;迅速在NLP 社区崭露头角&#xff0c;打破了过去30 年的记录。BERT、T5 和GPT 等模型现在已成为计算机视觉、语音识别、翻译、蛋白质测序、编码等各个领域中新应用的基础构件。…

es、MySQL 深度分页问题

文章目录 es 深度分页MySQL 深度分页 es 深度分页 es 深度分页问题&#xff0c;有点忘记了&#xff0c;这里记录一下 当索引库中有10w条数据&#xff0c;比如是商品数据&#xff1b;用户就是要查在1w到后10条数据&#xff0c;怎么查询。 es查询是从各个分片中取出前1w到后10条数…

redis 从0到1完整学习 (五):集合 IntSet 数据结构

文章目录 1. 引言2. redis 源码下载3. IntSet 数据结构4. 参考 1. 引言 前情提要&#xff1a; 《redis 从0到1完整学习 &#xff08;一&#xff09;&#xff1a;安装&初识 redis》 《redis 从0到1完整学习 &#xff08;二&#xff09;&#xff1a;redis 常用命令》 《redi…

JavaOOP篇----第十篇

系列文章目录 文章目录 系列文章目录前言一、构造方法能不能显式调用?二、什么是方法重载?三、构造方法能不能重写?能不能重载?四、内部类与静态内部类的区别?前言 前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站,…

Springboot启动异常 OgnlException: sqlSelect [java.lang.NoSuchMethodError

完整的日志如下&#xff1a; Invocation of init method failed; nested exception is org.mybatis.spring.MyBatisSystemException: nested exception is org.apache.ibatis.builder.BuilderException: Error evaluating expression ew ! null and ew.sqlSelect ! null. Cause…

协作机器人(Collaborative-Robot)安全碰撞的速度与接触力

协作机器人&#xff08;Collaborative-Robot&#xff09;的安全碰撞速度和接触力是一个非常重要的安全指标。在设计和使用协作机器人时&#xff0c;必须确保其与人类或其他物体的碰撞不会对人员造成伤害。 对于协作机器人的安全碰撞速度&#xff0c;一般会设定一个上限值&…

Excel排序怎么做?记好这些正确操作!

“我是个职场新手&#xff0c;对excel的使用还不是很熟悉。但是我需要处理一份文件。有朋友可以简单介绍一下excel排序的操作方法吗&#xff1f;” Excel作为一个实用的办公工具&#xff0c;给用户带来了很多的方便。在使用excel时&#xff0c;排序功能是比较重要且常用的。我们…

轴承故障诊断分类模型全家桶-最全教程

Python轴承故障诊断 (一)短时傅里叶变换STFT-CSDN博客 Python轴承故障诊断 (二)连续小波变换CWT-CSDN博客 Python轴承故障诊断 (三)经验模态分解EMD-CSDN博客 Pytorch-LSTM轴承故障一维信号分类(一)-CSDN博客 Pytorch-CNN轴承故障一维信号分类(二)-CSDN博客 Pytorch-Trans…

打造明厨亮灶工程,需要哪些AI视频智能算法助力?

旭帆科技AI智能监控可以通过摄像头、传感器和数据处理等技术手段&#xff0c;实时监测厨房人员着装、行为与烟火等&#xff0c;对厨房实时监控进行分析与记录&#xff0c;从而实现明厨亮灶场景的搭建&#xff0c;保障食品安全和服务质量。 1、烟火识别 对于后厨来说&#xff0…

搭建动态网站之——基于Redhat8.6搭建Discuz论坛

目录 一、动态网站与静态网站区别 1、提供用户互动接口的动态网站 2、搭建动态网站的需求&#xff1a; 二、搭建步骤 第一步&#xff1a;www服务器配置 第二步;编辑网页文件 第三步&#xff1a;使用xftp 将Discuz包传到/discuz解压 1、将Discuz包移动到/discuz 2、解压…

双燃料发动机,预计2025年市场规模将达到39亿美元

双燃料发动机是一种可以使用两种不同类型的燃料&#xff08;通常是天然气和柴油&#xff09;运行的发动机&#xff0c;具有更大的灵活性和更低的排放。近年来&#xff0c;在对更清洁、更高效能源的需求不断增长的推动下&#xff0c;双燃料发动机市场增长迅速。 全球市场&#x…

End-to-End Object Detection with Transformers(2020)

文章目录 AbstractIntroductionThe DETR modelObject detection set prediction loss二元匹配匈牙利损失如下Bounding box loss DETR architecture Conclusion hh 源代码 Abstract 我们提出了一种将目标检测视为直接集预测问题的新方法。我们的方法简化了检测管道&#xff0c;…

VUE中的index.html、App.vue和main.js的关系

VUE中的index.html、App.vue和main.js的关系&#xff0c;个人理解。 javascriptCopy code import Vue from vue; import App from ./App.vue;new Vue({render: h > h(App), }).$mount(#app);

【工具与中间件】通过飞书应用操作云文档

文章目录 前言1. 准备工作1.1 创建应用1.2 创建文件夹 2. 测试租户/个人版实践2.1 权限配置2.2 控制台调试2.3 协作文档添加应用2.4 CRUD2.4.1 根据文档描述选择token并生成2.4.2 新增多维表格数据API2.4.3 删除多维表格数据API2.4.4 查询多维表格数据API2.4.5 修改多维表格数据…

CentOS7 安装 DockerCompose

目录 一、安装Docker 二、安装步骤 2.1 卸载 2.2 安装docker 2.3 启动docker 2.4 配置镜像加速器 一、安装Docker Docker 分为 CE 和 EE 两大版本。 CE 即社区版(免费&#xff0c;支持周期7个月)EE 即企业版强调安全&#xff0c;付费使用&#xff0c;支持周期 24 个月…

java连接PRINTRONIX T8000打印机打印标签及常见打印错误说明

需要注意的点&#xff1a;数据拼接时一定要在数据两边加上双引号&#xff0c;否则打印出来的东西会报错&#xff01;&#xff01;&#xff01; package com.tscsdk;import java.io.IOException; import java.net.Socket; import java.text.SimpleDateFormat; import java.util…