【QT】 QT开发PDF阅读器

news2024/11/17 23:54:17

很高兴在雪易的CSDN遇见你 ,给你糖糖

欢迎大家加入雪易社区-CSDN社区云 


前言

本文分享QT开发PDF阅读器技术,希望对各位小伙伴有所帮助!

感谢各位小伙伴的点赞+关注,小易会继续努力分享,一起进步!

你的点赞就是我的动力(^U^)ノ~YO

结果展示:

我将收获到的:

        1. 如何创建PDFViewer

        2.创建PDFViewer所依赖的QT库

        3.PDFViewer的用处

目录

前言

1.准备PDFViewer所依赖的库

2.创建PDF Viewer

小结:


1.准备PDFViewer所依赖的库

        》使用开发的QT版本:5.15.2

        》存在问题:不能直接添加PDF模块

        》原因:QT5.15.2版本已带有pdf模块,但并未在include中包含,但是在lib和bin目录下能找到相应的.lib和.dll文件。

        》解决方案:

                》下载QT5.15.2源码

                》将“Qt\5.15.2\Src\qtwebengine\include”文件夹下的QtPdf和QtPdfWidgets复制到“Qt\5.15.2\msvc2019_64\include”文件夹下。

                》 将“Qt\5.15.2\Src\qtwebengine\src\pdf\api”文件夹下的.h文件复制到“Qt\5.15.2\msvc2019_64\include\QtPdf”文件夹下。

                》 将“Qt\5.15.2\Src\qtwebengine\src\pdfwidgets”文件夹下的.h文件复制到“Qt\5.15.2\msvc2019_64\include\QtPdfWidgets”文件夹下 

                 》我已将QtPdf整理成单独的依赖库,需要的小伙伴可以联系我下载。

                    也上传CSDN,下载地址:QT开发PDF阅读器,代码简洁易用!资源-CSDN文库 

2.创建PDF Viewer

        》创建UI文件

        》核心为PageSelector(页面选择)和ZoomSelector(缩放)

        》下载地址:QT开发PDF阅读器,代码简洁易用!资源-CSDN文库

        》代码如下:

        PageSelector.h文件

#ifndef PAGESELECTOR_H
#define PAGESELECTOR_H

#include <QWidget>

class QLabel;
class QLineEdit;
class QPdfDocument;
class QPdfPageNavigation;
class QToolButton;

class PageSelector : public QWidget
{
    Q_OBJECT

public:
    explicit PageSelector(QWidget *parent = nullptr);

    void setPageNavigation(QPdfPageNavigation *pageNavigation);

private slots:
    void onCurrentPageChanged(int page);
    void pageNumberEdited();

private:
    QPdfPageNavigation *m_pageNavigation;

    QLineEdit *m_pageNumberEdit;
    QLabel *m_pageCountLabel;
    QToolButton *m_previousPageButton;
    QToolButton *m_nextPageButton;
};

#endif // PAGESELECTOR_H

        PageSelector.cpp文件

#include "pageselector.h"

#include <QHBoxLayout>
#include <QLabel>
#include <QLineEdit>
#include <QPdfPageNavigation>
#include <QToolButton>

PageSelector::PageSelector(QWidget *parent)
    : QWidget(parent)
    , m_pageNavigation(nullptr)
{
    QHBoxLayout *layout = new QHBoxLayout(this);

    m_previousPageButton = new QToolButton(this);
    m_previousPageButton->setText("<");
    m_previousPageButton->setEnabled(false);

    m_pageNumberEdit = new QLineEdit(this);
    m_pageNumberEdit->setAlignment(Qt::AlignRight);

    m_pageCountLabel = new QLabel(this);
    m_pageCountLabel->setText("0");

    m_nextPageButton = new QToolButton(this);
    m_nextPageButton->setText(">");
    m_nextPageButton->setEnabled(false);

    layout->addWidget(m_previousPageButton);
    layout->addWidget(m_pageNumberEdit);
    layout->addWidget(m_pageCountLabel);
    layout->addWidget(m_nextPageButton);
}

void PageSelector::setPageNavigation(QPdfPageNavigation *pageNavigation)
{
    m_pageNavigation = pageNavigation;

    connect(m_previousPageButton, &QToolButton::clicked, m_pageNavigation, &QPdfPageNavigation::goToPreviousPage);
    connect(m_pageNavigation, &QPdfPageNavigation::canGoToPreviousPageChanged, m_previousPageButton, &QToolButton::setEnabled);

    connect(m_pageNavigation, &QPdfPageNavigation::currentPageChanged, this, &PageSelector::onCurrentPageChanged);
    connect(m_pageNavigation, &QPdfPageNavigation::pageCountChanged, this, [this](int pageCount){ m_pageCountLabel->setText(QString::fromLatin1("/ %1").arg(pageCount)); });

    connect(m_pageNumberEdit, &QLineEdit::editingFinished, this, &PageSelector::pageNumberEdited);

    connect(m_nextPageButton, &QToolButton::clicked, m_pageNavigation, &QPdfPageNavigation::goToNextPage);
    connect(m_pageNavigation, &QPdfPageNavigation::canGoToNextPageChanged, m_nextPageButton, &QToolButton::setEnabled);

    onCurrentPageChanged(m_pageNavigation->currentPage());
}

void PageSelector::onCurrentPageChanged(int page)
{
    if (m_pageNavigation->pageCount() == 0)
        m_pageNumberEdit->setText(QString::number(0));
    else
        m_pageNumberEdit->setText(QString::number(page + 1));
}

void PageSelector::pageNumberEdited()
{
    if (!m_pageNavigation)
        return;

    const QString text = m_pageNumberEdit->text();

    bool ok = false;
    const int pageNumber = text.toInt(&ok);

    if (!ok)
        onCurrentPageChanged(m_pageNavigation->currentPage());
    else
        m_pageNavigation->setCurrentPage(qBound(0, pageNumber - 1, m_pageNavigation->pageCount() - 1));
}

        ZoomSelector.h文件

#ifndef ZOOMSELECTOR_H
#define ZOOMSELECTOR_H

#include <QComboBox>
#include <QPdfView>

class ZoomSelector : public QComboBox
{
    Q_OBJECT

public:
    explicit ZoomSelector(QWidget *parent = nullptr);

public slots:
    void setZoomFactor(qreal zoomFactor);

    void reset();

signals:
    void zoomModeChanged(QPdfView::ZoomMode zoomMode);
    void zoomFactorChanged(qreal zoomFactor);

private slots:
    void onCurrentTextChanged(const QString &text);
};

#endif // ZOOMSELECTOR_H

        ZoomSelector.cpp文件

#include "zoomselector.h"

#include <QLineEdit>

ZoomSelector::ZoomSelector(QWidget* parent)
    : QComboBox(parent)
{
    setEditable(true);

    addItem(QLatin1String("Fit Width"));
    addItem(QLatin1String("Fit Page"));
    addItem(QLatin1String("12%"));
    addItem(QLatin1String("25%"));
    addItem(QLatin1String("33%"));
    addItem(QLatin1String("50%"));
    addItem(QLatin1String("66%"));
    addItem(QLatin1String("75%"));
    addItem(QLatin1String("100%"));
    addItem(QLatin1String("125%"));
    addItem(QLatin1String("150%"));
    addItem(QLatin1String("200%"));
    addItem(QLatin1String("400%"));

    connect(this, static_cast<void(QComboBox::*)(const QString&)>(&QComboBox::currentIndexChanged),
        this, &ZoomSelector::onCurrentTextChanged);

    connect(lineEdit(), &QLineEdit::editingFinished,
        this, [this]() {onCurrentTextChanged(lineEdit()->text()); });
}

void ZoomSelector::setZoomFactor(qreal zoomFactor)
{
    setCurrentText(QString::number(qRound(zoomFactor * 100)) + QLatin1String("%"));
}

void ZoomSelector::reset()
{
    setCurrentIndex(8); // 100%
}

void ZoomSelector::onCurrentTextChanged(const QString& text)
{
    if (text == QLatin1String("Fit Width")) {
        emit zoomModeChanged(QPdfView::FitToWidth);
    }
    else if (text == QLatin1String("Fit Page")) {
        emit zoomModeChanged(QPdfView::FitInView);
    }
    else {
        qreal factor = 1.0;

        QString withoutPercent(text);
        withoutPercent.remove(QLatin1Char('%'));

        bool ok = false;
        const int zoomLevel = withoutPercent.toInt(&ok);
        if (ok)
            factor = zoomLevel / 100.0;

        emit zoomModeChanged(QPdfView::CustomZoom);
        emit zoomFactorChanged(factor);
    }
}

小结:

        本文主要分享了开发PDF阅读器所依赖的库,以及开发的过程,谢谢各位小伙伴的关注。

感谢各位小伙伴的点赞+关注,小易会继续努力分享,一起进步!

你的赞赏是我的最最最最大的动力(^U^)ノ~YO

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

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

相关文章

python流星雨特效代码微信,python流星雨特效代码源

大家好&#xff0c;小编为大家解答python流星雨特效代码需要什么模块的问题。很多人还不知道python流星雨特效代码微信&#xff0c;现在让我们一起来看看吧&#xff01; # -*- coding:utf-8 -*- # 导入系统文件库 import pygame import random from pygame.locals import * fr…

Python爬虫都喜欢用的防封招式!

你是否在爬取数据的时候被网站的IP封锁问题困扰过&#xff1f;别担心&#xff0c;我来教你如何使用爬虫ip&#xff0c;轻松解决这个问题并提升你的爬虫效率&#xff01;快来跟我学&#xff0c;让你的Python爬虫变得更牛&#xff01; 首先&#xff0c;让我来和你解释一下什么是爬…

基于神经网络的心脏病健康系统

基于神经网络的心脏病健康系统 导语 这篇文章旨在记录该系统设计的过程&#xff0c;同时指导从零开始搭建本健康系统的环境&#xff0c;并在自己的电脑上把这个心脏病健康系统run起来。 下面是这个文件夹下各个文件的介绍&#xff1a; .\心脏病预测 ├─build --- 该系…

MYSQL进阶-查询优化- 实战 STATUS

回城传送–》《100天精通MYSQL从入门到就业》 文末有送书活动&#xff0c;可以参加&#xff01; 文章目录 一、练习题目二、SQL思路SQL进阶-查询优化- SHOW STATUS初始化数据解法SHOW STATUS是什么实战经验&#xff1a;常用的mysql状态查询1、QPS(每秒处理的请求数量)计算思路…

PyTorch 微调终极指南:第 1 部分 — 预训练模型及其配置

一、说明 如今&#xff0c;在训练深度学习模型时&#xff0c;通过在自己的数据上微调预训练模型来迁移学习已成为首选方法。通过微调这些模型&#xff0c;我们可以利用他们的专业知识并使其适应我们的特定任务&#xff0c;从而节省宝贵的时间和计算资源。本文分为四个部分&…

还不知道Java类加载机制,你算白学了

1 前言 在Java的世界里&#xff0c;每一个类或者接口&#xff0c;在经历编译器后&#xff0c;都会生成一个个.class文件。类加载机制指的是将这些.class文件中的二进制数据读入到内存中&#xff0c;并对数据进行校验&#xff0c;解析和初始化。最终&#xff0c;每一个类都会在…

Not All Features Matter:Enhancing Few-shot CLIP with Adaptive Prior Refinement

APE是ICCV2023的一篇文章&#xff0c;也是我在这个领域里接触的第一篇文章&#xff0c;这里主要做一下记录。 论文链接&#xff1a;2304.01195.pdf (arxiv.org) 代码链接&#xff1a;yangyangyang127/APE: [ICCV 2023] Code for "Not All Features Matter: Enhancing Fe…

【深度学习注意力机制系列】—— SKNet注意力机制(附pytorch实现)

SKNet&#xff08;Selective Kernel Network&#xff09;是一种用于图像分类和目标检测任务的深度神经网络架构&#xff0c;其核心创新是引入了选择性的多尺度卷积核&#xff08;Selective Kernel&#xff09;以及一种新颖的注意力机制&#xff0c;从而在不增加网络复杂性的情况…

立即开始使用 3D 图像

一、说明 这个故事介绍了使用这种类型的数据来训练机器学习3D模型。特别是&#xff0c;我们讨论了Kaggle中可用的MNIST数据集的3D版本&#xff0c;以及如何使用Keras训练模型识别3D数字。 3D 数据无处不在。由于我们希望构建AI来与我们的物理世界进行交互&#xff0c;因此使用3…

安装LED透明屏需要注意这4点

随着LED显示屏的广泛应用&#xff0c;各种大屏幕随处可见。透明LED显示屏的安装方法多种多样&#xff0c;涵盖了屋顶式、立柱式、挂式、壁挂式和镶嵌式等多种方式。虽然安装LED透明屏不像安装空调等广告载体那样简单&#xff0c;但也并非极其复杂。考虑到LED透明屏的特殊性&…

LM+retrieval

retrievalLM https://acl2023-retrieval-lm.github.io/ 在input层利用retrieval信息 主要是通过通过相似度计算或者重要性计算在datasets中得到与询问x最相关的k个document,讲文档放在询问x前面组成新的LM的输入&#xff0c;获取额外知识以回答问题。 在intermediate layer…

nacos2.2.3 删除永久实例

问题描述 在nacos2.2.3中删除非临时性实例 报错 解决方案 在命令行下执行命令&#xff1a; curl -X DELETE "http://127.0.0.1:8848/nacos/v1/ns/instance?serviceNamenacos-restTemplate-stock&groupNameDEFAULT_GROUP&namespaceIdpublic&ip192.168.1…

全网最牛,接口自动化-Linux系统安装Jenkins+Ant详细步骤

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 在Linux系统上安装…

GPT-4助力数据分析:提升效率与洞察力的未来关键技术 | 京东云技术团队

摘要 随着大数据时代的到来&#xff0c;数据分析已经成为企业和组织的核心竞争力。然而&#xff0c;传统的数据分析方法往往无法满足日益增长的数据分析需求的数量和复杂性。在这种背景下&#xff0c;ChatGPT-4作为一种先进的自然语言处理技术&#xff0c;为数据分析带来了革命…

FastAPI和Flask:构建RESTful API的比较分析

Python 是一种功能强大的编程语言&#xff0c;广泛应用于 Web 开发领域。FastAPI 和 Flask 是 Python Web 开发中最受欢迎的两个框架。本文将对 FastAPI 和 Flask 进行综合对比&#xff0c;探讨它们在语法和表达能力、生态系统和社区支持、性能和扩展性、开发工具和调试支持、安…

一键批量删除文件名中的空格,轻松整理您的文件

随着数字化时代的到来&#xff0c;我们的电脑里积攒了越来越多的文件&#xff0c;但是随之而来的问题是&#xff0c;文件名中的空格可能会导致一些不便和混乱。为了解决这一问题&#xff0c;我们开发了一款便捷实用的工具&#xff0c;可以一键批量删除文件名中的空格&#xff0…

ORM 之 阿里 Fluent-Mybatis主推动态SQL 你学废了吗?

Mybatis作为在东亚开发者市场上占有绝对的使用优势&#xff0c;在中国大陆上讨论Mybatis优化的项目也是挺活跃。 局限于原始Mybatis繁琐的流程&#xff0c;自动代码生成、声明式SQL、动态SQL&#xff0c;以及诸多细节的内容&#xff1a;多租户、多数据源、数据脱敏、SQL审计、…

MyBatis查询数据库之三(#{}vs${},like查询,resultMap,as,多表查询)

目录 查询操作 1.单表查询 1.1 参数占位符#{}和${} 1.2 ${}的优点 1.3 sql注入问题 ​编辑 面试常问&#xff1a;${}与#{}的区别 1.4 like查询 2.多表查询 2.1 返回字典映射&#xff1a;resultMap 2.2 多表查询 &#xff08;1&#xff09;建立 Articalinfo 实体类&a…

所有AI图都在这了

最近一直在玩AI生图&#xff0c;有点拔不出来了&#xff0c;喜欢生图的感觉&#xff0c;日积月累&#xff0c;已经有几千张图片了&#xff0c;想把这些图片都分享出来给大家欣赏&#xff0c;云盘、图片APP&#xff0c;感觉都不好用&#xff0c;最后熬夜码了一个属于自己的图片管…

(树) 剑指 Offer 68 - II. 二叉树的最近公共祖先 ——【Leetcode每日一题】

❓剑指 Offer 68 - II. 二叉树的最近公共祖先 难度&#xff1a;简单 给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。 百度百科 中最近公共祖先的定义为&#xff1a;“对于有根树 T 的两个结点 p、q&#xff0c;最近公共祖先表示为一个结点 x&#xff0c;满足 x 是…