500 行代碼實現 PDF 閱讀器

經過兩週的迭代,現在我們的 PyReadon 已經具備一般的 PDF 閱讀器的基本功能:

  • 添加書籍
  • 刪除書籍
  • 閱讀書籍
  • 保存記錄
  • 查看書籍信息

前幾版相比較,這一版優化了書籍的數據結構,支持同時閱讀多本書,支持鼠標左鍵翻頁,並通過與 sqlite3 數據庫的交互來保存書庫以及書籍信息(地址、頁數等)。

500 行代碼實現 PDF 閱讀器

書籍

使用 Book 類來保存書籍信息,比如元數據、頁數以及閱讀與否的信息。通過 __eq__ 特殊方法,來判斷兩個 book 實例是否為同一對象。

500 行代碼實現 PDF 閱讀器

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

同時閱讀

500 行代碼實現 PDF 閱讀器

通過內部維護一個 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()

查看書籍信息

500 行代碼實現 PDF 閱讀器

書籍支持查看右鍵菜單,我們使用 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 上。


分享到:


相關文章: