500 行代码实现 PDF 阅读器

经过两周的迭代,现在我们的 PyReadon 已经具备一般的 PDF 阅读器的基本功能:

  • 添加书籍
  • 删除书籍
  • 阅读书籍
  • 保存记录
  • 查看书籍信息

前几版相比较,这一版优化了书籍的数据结构,支持同时阅读多本书,支持鼠标左键翻页,并通过与 sqlite3 数据库的交互来保存书库以及书籍信息(地址、页数等)。

书籍

使用 Book 类来保存书籍信息,比如元数据、页数以及阅读与否的信息。通过 __eq__ 特殊方法,来判断两个 book 实例是否为同一对象。

class Book:
    def __init__(self, fname):
        # 文件名
        self.fname = fname
        # 是否被阅读
        self.flag = None
        self._info = None
        self._page = 0
        self.get_meta_data(self.fname)

    def __eq__(self, other):
        if hasattr(other, 'fname'):
            return self.fname == other.fname
        return False        

同时阅读

通过内部维护一个 read_list 列表来实现同时阅读多本书。列表储存 book 对象,每个 book 对象都有一个 page 属性。这样,我们的程序就能记住每本书被翻到的页数了。

第二行代码,是对 read_list 进行初始化。book.flag 用来判断这本书上次关闭前是否处于阅读的状态。如果是,我们就把它放在阅读列表中。

self.read_list = [None]
self.read_list.extend(book for book in self.booklist if book.flag)

左键翻页

我们重写 MyArea 类的 mousePressEvent 方法。event.pos() 函数用来获取鼠标的坐标,x() 用来获取横坐标。

width 为 MyArea 区域的宽度,如果点击鼠标左键,且鼠标位置的横坐标小于 1/3 区域宽度,那么向前翻页;大于 2/3 区域宽度,那么向后翻页。

# 鼠标左键翻页
def mousePressEvent(self, event):
    pos = event.pos().x()
    width = self.size().width()
    if event.button() == Qt.LeftButton:
        if pos > width * 2 / 3:
            self.right()
        elif pos < width / 3:
            self.left()

sqlite3

sqlite3 是轻量型本地数据库,具有无服务器、零配置、速度快等特点。

PyReadon 启动时,会从数据库中读取图书信息。read_db 函数主要执行以下功能:

如果路径中不存在 PDF.db 数据库,那么就新建 PDF.db 数据库,并且创建一个 book_info 表格,该表格拥有三个属性 path, page, flag;

从 book_info 表格中读取数据,并创建 book 对象来接收这些数据,最后通过 yield 函数返回 book 对象。

book_db = 'PDF.db'
book_info = namedtuple('info',  'path page flag')


def read_db():
    # 将路径更改为该文件所处路径
    os.chdir(os.path.dirname(os.path.realpath(__file__)))
    if not os.path.exists(book_db):
        conn = sqlite3.connect(book_db)
        conn.execute("CREATE TABLE book_info(path, page, flag)")
        conn.close()
    conn = sqlite3.connect(book_db)
    for row in conn.execute('SELECT * FROM book_info'):
        info = book_info(*row)
        book = Book(info.path)
        book.page = info.page
        book.flag = info.flag
        yield book

    conn.close()  

将数据存储到数据库中:

将书籍列表传给 save2db 函数,通过列表推导式创建 book 所在地址的列表。conn.executemany 函数将迭代生成器表达式,并获得 书籍地址、阅读页数、是否在阅读列表中 等信息,最后将这些信息存储在数据库中。

def save2db(booklist):
    conn = sqlite3.connect(book_db)
    conn.executemany("INSERT INTO book_info Values (?,?,?)",
                ((book.fname, book.page, book.flag) for book in booklist))
    conn.commit()
    conn.close()

在进行存储数据之前,我们首先要将 book_info 数据库中的内容清空。

def remove_db():
    conn = sqlite3.connect(book_db)
    conn.execute('DELETE FROM book_info')
    conn.commit()
    conn.close()

查看书籍信息

书籍支持查看右键菜单,我们使用 QMessageBox.about 函数来显示书籍信息。

elif action == item3:
    index = row_num * 8 + col_num
    # 之后改成 book
    book = self.booklist[index]
    info = book.info
    fmt = f'路径:{info.path}\n\n' \
        f'格式:{info.format}\n\n' \
        f'标题:{info.title}\n\n' \
        f'作者:{info.author}\n\n' \
        f'Creator:{info.creator}\n\n' \
        f'Producer:{info.producer}\n\n'

    QMessageBox.about(self, '文档信息', fmt)

弹窗

通过 Qt Designer 设计了一个弹窗,并与主程序绑定:

info 即为弹窗,点击工具栏中的信息栏时会弹出窗口。

info = Info()
reader.infobar.triggered.connect(info.show)

以上就是本文的全部内容了,觉得不错的朋友可以点赞、或者转发支持,源代码已经上传到到我的 Github :https://github.com/cassieeric/Python-Application,感兴趣的小伙伴可以去学习一下。

------------------- End -------------------

本文分享自微信公众号 - Python爬虫与数据挖掘(crawler_python)

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2019-07-02

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏腾讯云数据库(TencentDB)

最大民营银行和小程序·云开发背后的数据库架构分享,免费报名参加

6月29日,深圳,邀您参加《腾讯云数据库行业实战分享会》沙龙活动,您将获得: 1 .数据库在小程序·云开发中的应用解读,教你7天打造流量过亿的小程序! 2. ...

10220
来自专栏深度应用

[软件开发]·Windows系统安装MySQL简易教程

下载地址:https://dev.mysql.com/downloads/mysql/

16060
来自专栏百味科研芝士

手把手学习TCGA数据库:SNP突变分析第四期

各位科研芝士的朋友,大家好,又见面了,今天我们的主题是利用cBioportal及UCSC-XENA数据库在线下载TCGA_SNP数据

47420
来自专栏Java学习资料

怎么才能学好Java编程写好Java代码?

动力节点Java培训最新上线Java实验班,等你来测试自己适不适合学习Java编程哦!

13200
来自专栏深度应用

[MXNet逐梦之旅]练习五·使用MXNetFashionMNIST数据集CNN分类(对比CPU与GPU)

16930
来自专栏快乐学Python

Python 连接 MySQL 的几种姿势

尽管很多 NoSQL 数据库近几年大放异彩,但是像 MySQL 这样的关系型数据库依然是互联网的主流数据库之一,每个学 Python 的都有必要学好一门数据库,...

12940
来自专栏深度应用

[Django个人网站开发]·编写你的第一个 Django 应用-第 1 部分

我们假定你已经阅读了 安装 Django。你能知道 Django 已被安装,且安装的是哪个版本,通过在命令提示行输入命令(由 $ 前缀)。

9330
来自专栏Jerry的SAP技术分享

IBASE Level up - single parent navigation

6140
来自专栏呼延

Mysql的 If和 Case语句

比如在上例子中,我们存储了一些不希望暴露性别的用户,存储的值为3.此时想要查询可以:

35810
来自专栏Java架构沉思录

这几个Redis使用技巧,让你的程序快如闪电

实际上NewLife.Redis是一个完整的Redis协议功能的实现,但是Redis的核心功能并没有在这里面,而是在NewLife.Core里面。

16730

扫码关注云+社区

领取腾讯云代金券

年度创作总结 领取年终奖励