最后一篇七咧,這次我們加上幾個(gè)函數(shù),使得這個(gè)閱讀器能夠按照章節(jié)閱讀電子書靶庙,前兩篇我們將完成了Book模塊问畅,實(shí)現(xiàn)了電子書的數(shù)據(jù)抽象,然后寫了GUI六荒,完成了一個(gè)簡(jiǎn)單的功能护姆,在倉(cāng)庫(kù)中插入圖書,把LibraryTableWidget刷新掏击,使得圖書在library呈現(xiàn)签则,可以看到書名,作者铐料。接下來(lái)我們完善這個(gè)程序渐裂。
- 載入書籍的章節(jié)
效果是這樣的:
首先豺旬,我們?cè)贐ookView模塊中加入這樣一個(gè)函數(shù):
def load_book(self, book_id):
self.book = Book(book_id)
self.chapter_list.clear()
for chapter in self.book.chapters:
self.chapter_list.addItem(chapter[0])
self.chapter_list.setCurrentRow(0)
根據(jù)book_id(也就是epub文件名),刷新chapter_list的內(nèi)容柒凉,把每個(gè)章節(jié)的名稱作為QListWidget的item添加進(jìn)來(lái)族阅。
然后,什么時(shí)候讓這個(gè)函數(shù)起作用膝捞,怎么讓這個(gè)函數(shù)起作用坦刀?我們要求的邏輯是雙擊Library的Item,然后載入這本書的章節(jié)蔬咬。這里就要用到Qt的信號(hào)槽機(jī)制了鲤遥,網(wǎng)上關(guān)于Qt信號(hào)槽機(jī)制的文章很多,書本上也有介紹林艘,大多都是balabala說(shuō)一大堆盖奈,堆概念堆名詞,我嘗試用幾句話來(lái)說(shuō)說(shuō)這個(gè)機(jī)制的核心狐援。其實(shí)它跟IFTTT(if this then that)這個(gè)工具是很像的钢坦,一個(gè)對(duì)象發(fā)送信號(hào),另一個(gè)對(duì)象接收到信號(hào)就做出相應(yīng)的動(dòng)作啥酱,為什么要這樣設(shè)計(jì)呢爹凹?其實(shí)我們可以嘗試思考Qt設(shè)計(jì)者的初衷,因?yàn)檫@個(gè)過(guò)程是符合人類思考過(guò)程的镶殷,能夠讓編程更簡(jiǎn)單禾酱,如果了解了其他的GUI庫(kù)的事件處理方式,如Java的監(jiān)聽(tīng)機(jī)制绘趋,WFT的消息映射颤陶,就能發(fā)覺(jué)Qt的signal/slot機(jī)制有多好了,理解了這一點(diǎn)埋心,再去看這方面的資料就能得心應(yīng)手指郁。
這里沒(méi)有談Qt信號(hào)槽的細(xì)節(jié),我只是提出一種思考方式拷呆,因?yàn)槲乙彩浅鯇W(xué)者闲坎,但這種思考方式能讓我們?cè)谟龅缴蕴貏e的細(xì)節(jié)時(shí)會(huì)不感到詫異,比如茬斧,連接信號(hào)和槽的connect函數(shù)可以使得信號(hào)和信號(hào)連接腰懂,一個(gè)button發(fā)送了一個(gè)click()信號(hào),于是asignal()信號(hào)也發(fā)送了项秉,就如一個(gè)人頭疼绣溜,他沒(méi)有直接叫醫(yī)生,而是通知了朋友娄蔼,讓朋友幫忙叫醫(yī)生怖喻,又比如一個(gè)信號(hào)可以和多個(gè)槽連接底哗,就如一個(gè)人頭疼,他發(fā)了一條朋友圈锚沸,于是當(dāng)醫(yī)生的朋友都來(lái)了跋选。。哗蜈。前标。這些過(guò)程都是容易理解的,是符合人類思考過(guò)程的距潘。
好了炼列,瞎扯淡環(huán)節(jié)結(jié)束,我們繼續(xù)音比。讓chapter_list的雙擊Item事件與book_view的load_book函數(shù)綁定俭尖,我們可以在LibraryTableWidget中加上:
def create_connections(self):
self.connect(self, SIGNAL("itemDoubleClicked(QTableWidgetItem *)"), self.view_book)
def view_book(self):
book_id = self.library['books'][self.currentRow()]['id']
self.book_view.load_book(book_id)
當(dāng)然,也需要在LibraryTableWidget, __init__
函數(shù)中加上 :
self.create_connections()
完成之后硅确,再運(yùn)行main.py就能實(shí)現(xiàn)上面展示的內(nèi)容目溉。
- web_view顯示圖書內(nèi)容的部分
其實(shí)跟上面的方式大同小異明肮,依葫蘆畫瓢菱农, 我就直接給出代碼了:
在Book模塊中加上
def get_chapter(self, num):
return self.f.read(self.oebps_folder+self.chapters[num][1])
根據(jù)章節(jié)數(shù)目獲得html文件內(nèi)容
在BookView中加上
def set_chapter(self, num=None):
if num is None:
num = self.chapter_list.currentRow()
if num < 0:
num = len(self.book.chapters) - 1
elif num >= len(self.book.chapters):
num = 0
self.web_view.setHtml(self.book.get_chapter(num).decode(encoding="utf-8"))
使得web_view可以根據(jù)章節(jié)數(shù)目顯示電子書中該章節(jié)的內(nèi)容
同樣在BookView的__init__
函數(shù)中加上:
self.create_connections()
綁定signal/slot, 在BookView中加上create_connection函數(shù):
def create_connections(self):
chlist = self.chapter_list
self.connect(self.next_button, SIGNAL("clicked()"), lambda:
chlist.setCurrentRow(0
if chlist.currentRow() == chlist.count() - 1
else chlist.currentRow() + 1))
self.connect(self.previous_button, SIGNAL("clicked()"), lambda:
chlist.setCurrentRow(chlist.count() - 1
if chlist.currentRow() == 0
else chlist.currentRow() - 1))
self.connect(self.chapter_list, SIGNAL("currentRowChanged(int)"),
self.set_chapter)
page = self.web_view.page()
page.setLinkDelegationPolicy(QWebPage.DelegateAllLinks)
self.connect(page, SIGNAL("linkClicked(const QUrl&)"),
self.link_clicked)
最終的效果:
最后,給出源代碼地址