PyQt5 從零開始制作 PDF 閱讀器(二)

上一篇文章中颠蕴,我們實(shí)現(xiàn)了 PDF 閱讀器的初始界面拉鹃。這一次,新增了閱讀功能,可以實(shí)現(xiàn)基本的翻頁以及縮放等操作员舵。不過,暫時(shí)只可以同時(shí)閱讀一本書萝快。

下圖為效果圖:

在這里插入圖片描述

下面我來介紹下川蒙,這次主要新增的功能:

選項(xiàng)卡

QTabWidget 可以允許我們?cè)谝粋€(gè)窗口顯示多個(gè)頁面。對(duì)于書庫的這個(gè)選項(xiàng)卡,頁面顯示為 self.table ,即初始界面

self.table(QTableWidget) -> self.tabwidget(QTabWidge)蹈矮。

# 初始化選項(xiàng)卡
self.tabwidget = QTabWidget()
# 添加書庫選項(xiàng)卡
self.tabwidget.addTab(self.table, '書庫')
self.setCentralWidget(self.tabwidget)
# 設(shè)置選項(xiàng)卡可以關(guān)閉
self.tabwidget.setTabsClosable(True)
# 點(diǎn)擊選項(xiàng)卡叉號(hào)時(shí)砰逻,執(zhí)行 removeTabab 操作
self.tabwidget.tabCloseRequested[int].connect(self.remove_tab)

新建選項(xiàng)卡:每次開始閱讀時(shí),新建一個(gè)選項(xiàng)卡泛鸟,名稱為文件名蝠咆。

def read_book(self, fname):
    # self.close()
    # 內(nèi)存有可能泄露
    self.doc = fitz.open(fname)
    # metadata = doc.metadata
    title = fname.split('/' or '\\')[-1].replace('.pdf', '')

    vbox = self.book_area(self.doc.loadPage(0))
    self.book_add_tab(title, vbox)

其中,我們要求主選項(xiàng)卡谈况,即書庫選項(xiàng)卡是不可以關(guān)閉的勺美。

def remove_tab(self, index):
    if index:
        # 當(dāng)前頁數(shù)
        self.current_page = 0
        self.tabwidget.removeTab(index)
        # 正在閱讀的書
        self.read_list.pop(index)

閱讀界面的選項(xiàng)卡對(duì)應(yīng)的頁面區(qū)域?yàn)?QScrollArea 递胧,QScrollArea 支持滾輪操作。也就是說赡茸,如果我們縮放 PDF 頁面大小超過 QScrollArea 的大小缎脾,那么就會(huì)自動(dòng)出現(xiàn)滾輪,以便我們?yōu)g覽頁面占卧。其中遗菠,MyArea 類是對(duì) QScrollArea 的重載,綁定了快捷鍵以支持翻頁以及縮放等操作华蜒。

Pixmap -> label -> area(MyArea) -> vbox(QVBoxLayout) -> tab(QWidget) -> self.tabwidget(QTabWidge)辙纬。

def book_add_tab(self, title, vbox):
    tab = QWidget()
    tab.setLayout(vbox)
    # tab 為頁面,title 為標(biāo)簽名稱
    self.tabwidget.addTab(tab, title)
    
def book_area(self, page):
    label = self.page_pixmap(page)
    # area = QScrollArea()
    area = MyArea(self)
    area.init(self)
    area.setWidget(label)

    vbox = QVBoxLayout()
    vbox.addWidget(area)
    return vbox

下面我們來看看, MyArea 這個(gè)類該如何定義:

MyArea(QScrollArea)

這里,我們定義了 init 方法,用來接受 Reader 主類 的 self 參數(shù), 即通過 self.widget 調(diào)用 Reader 類的實(shí)例方法叭喜。

在 init_action 函數(shù)中,我們新建了四個(gè) QShortCut 實(shí)例贺拣,分別支持快捷鍵實(shí)現(xiàn)縮小、放大捂蕴、下一頁譬涡、上一頁的操作。

class MyArea(QScrollArea):
    def init(self, widget):
        self.widget = widget
        self.init_action()

    def init_action(self):
        zoom_minus = QShortcut(QKeySequence("Ctrl+-"), self)
        zoom_minus.activated.connect(self.minus)
        zoom_plus = QShortcut(QKeySequence("Ctrl+="), self)
        zoom_plus.activated.connect(self.plus)

        switch_left = QShortcut(QKeySequence(Qt.Key_Left), self)
        switch_left.activated.connect(self.left)
        switch_right = QShortcut(QKeySequence(Qt.Key_Right), self)
        switch_right.activated.connect(self.right)


    def plus(self):
        self.widget.zoom_book(plus=True)

    def minus(self):
        self.widget.zoom_book(plus=False)

    def right(self):
        self.widget.switch_page(right=True)

    def left(self):
        self.widget.switch_page(right=False)

下面啥辨,我們來介紹縮放與翻頁功能的具體實(shí)現(xiàn):

縮放功能

self.size 用來存儲(chǔ)頁面大小涡匀,self.page 正是根據(jù) self.size 來實(shí)現(xiàn)縮放功能。

def zoom_book(self, plus=True):
    a, b = self.size
    if plus:
        a += 0.4
        b += 0.4
        self.size = (a, b)
        self.set_page()
    elif not plus and a > 0:
        if a >= 1:
            a -= 0.4
            b -= 0.4
        self.size = (a, b)
        self.set_page()

Pixmap -> label -> area(MyArea) -> vbox(QVBoxLayout) -> tab(QWidget) -> self.tabwidget(QTabWidge)溉知。

tab 獲取 tab 對(duì)象陨瘩,layout 獲取 vbox 對(duì)象,widget 獲取 area 對(duì)象级乍,直接更改 area 上 label 控件舌劳。

def set_page(self):
    # 加載頁面
    page = self.doc.loadPage(self.current_page)
    # 獲取當(dāng)前 Widget
    tab = self.tabwidget.currentWidget()
    # 獲取當(dāng)前的 Layout
    layout = tab.layout()
    # 獲取 Layout 上的控件
    widget = layout.itemAt(0).widget()
    # 獲取已經(jīng)繪制好的 label 對(duì)象
    label = self.page_pixmap(page)
    # 將 widget 的內(nèi)容更改為現(xiàn)在的 label 對(duì)象
    widget.setWidget(label)

接著我們介紹如何實(shí)現(xiàn)翻頁功能

翻頁功能

這次,我們實(shí)現(xiàn)的 PDF 閱讀器只能同時(shí)閱讀一本書卡者,所以翻頁功能只需由 self.current_page 控制就行蒿囤。

self.doc.pageCount 為總頁數(shù),當(dāng)前頁數(shù)不能為負(fù)數(shù)或者大于總頁數(shù)崇决。更改完 self.current_page 之后材诽,就可以執(zhí)行 self.set_page 操作,直接更改 area 上的 label 控件恒傻。

def set_current_page(self, right):
    if right and self.current_page < self.doc.pageCount - 1:
        self.current_page += 1

    elif not right and self.current_page > 0:
        self.current_page -= 1
        
 

def switch_page(self, right=True):
    self.set_current_page(right)
    self.set_page()

關(guān)注微信公眾號(hào):Python高效編程脸侥,微信后臺(tái)回復(fù) 2019330 獲取源碼。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末盈厘,一起剝皮案震驚了整個(gè)濱河市睁枕,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖外遇,帶你破解...
    沈念sama閱讀 217,657評(píng)論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件注簿,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡跳仿,警方通過查閱死者的電腦和手機(jī)诡渴,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,889評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來菲语,“玉大人妄辩,你說我怎么就攤上這事∩缴希” “怎么了眼耀?”我有些...
    開封第一講書人閱讀 164,057評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)佩憾。 經(jīng)常有香客問我哮伟,道長(zhǎng),這世上最難降的妖魔是什么鸯屿? 我笑而不...
    開封第一講書人閱讀 58,509評(píng)論 1 293
  • 正文 為了忘掉前任澈吨,我火速辦了婚禮把敢,結(jié)果婚禮上寄摆,老公的妹妹穿的比我還像新娘。我一直安慰自己修赞,他們只是感情好婶恼,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,562評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著柏副,像睡著了一般勾邦。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上割择,一...
    開封第一講書人閱讀 51,443評(píng)論 1 302
  • 那天眷篇,我揣著相機(jī)與錄音,去河邊找鬼荔泳。 笑死蕉饼,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的玛歌。 我是一名探鬼主播昧港,決...
    沈念sama閱讀 40,251評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼支子!你這毒婦竟也來了创肥?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,129評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎叹侄,沒想到半個(gè)月后巩搏,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,561評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡趾代,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,779評(píng)論 3 335
  • 正文 我和宋清朗相戀三年塔猾,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片稽坤。...
    茶點(diǎn)故事閱讀 39,902評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡丈甸,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出尿褪,到底是詐尸還是另有隱情睦擂,我是刑警寧澤,帶...
    沈念sama閱讀 35,621評(píng)論 5 345
  • 正文 年R本政府宣布杖玲,位于F島的核電站顿仇,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏摆马。R本人自食惡果不足惜臼闻,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,220評(píng)論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望囤采。 院中可真熱鬧述呐,春花似錦、人聲如沸蕉毯。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,838評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽代虾。三九已至进肯,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間棉磨,已是汗流浹背江掩。 一陣腳步聲響...
    開封第一講書人閱讀 32,971評(píng)論 1 269
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留乘瓤,地道東北人环形。 一個(gè)月前我還...
    沈念sama閱讀 48,025評(píng)論 2 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像馅扣,于是被迫代替她去往敵國(guó)和親斟赚。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,843評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容