您的位置:首页 > 编程语言 > Python开发

python pyqt4 PyQT实现了使用QThread后台处理数据

2015-10-15 16:58 846 查看
python pyqt4 PyQT实现了使用QThread后台处理数据
2013-08-30 13:24:25

分类: Python/Ruby

原文地址:python pyqt4 PyQT实现了使用QThread后台处理数据 作者:leve1031

花了前后将近一个星期的时间,终于用PyQT实现了我的第一个程序。本程序实现了使用QThread后台处理数据、QThread的暂停,恢复、停止等功能。

主要有几个问题:

1、后台单独线程处理数据的问题;最初不明白QT在子线程中不能操作GUI的问题,因此查了很久的GUI的crash的问题

2、界面的布局;理解了gridLayout这个非常方便的布局方法。

代码片段

# -*- coding: utf-8
-*-

"""

Module implementing umd_MainWindow.

"""

import sys, os, re, time,sip

from PyQt4 import QtGui, QtCore

from dict4ini
import DictIni

from Ui_ebook_txt
import Ui_umd_MainWindow

class eBookException(Exception):

pass

class ebookParseWorker(QtCore.QThread):

'''QT中子线程内不能操作GUI界面,切记切记'''

def __init__(self, parent=None):

QtCore.QThread.__init__(self, parent)

self.exiting
= False

self.isWait=False

self.data={}

def setVar(self, name, value):

self.data[name]=value

def __del__(self):

self.exiting
= True

self.wait()

def buildRegx(self):

#self.alert(regx)

if self.data['chmChapterRegx']
is None:

regx='pages\[(\d+)\]\s*=\s*\[(.*)\];'

try:

self.chapterInfo=re.compile(self.data['chmChapterRegx'])

except:

self.alert('列表处理正则表达式不正确')

return False

self.chapterList=[]

return True

def getChapterList(self):

if os.path.exists(unicode(self.data['chmChapterJs']))
==False:

self.alert('章节列表JS文件%s不存在'%(self.data['chmChapterJs']))

return False

if self.data['inputCharset']
is None or self.data['inputCharset'].strip()=='':

self.data['inputCharset']='gbk'

m=self.chapterInfo.findall(open(unicode(self.data['chmChapterJs']),'rb').read())

vol=''

for x
in m:

oldChapterInfo=x[1].split(',')

newChapterInfo={}

if len(oldChapterInfo)==4:

if oldChapterInfo[3].strip('"').strip("'")[0:5]!='<1:

self.alert('章节列表小于1,请检查列表正则表达式是否正确')

return False

return self.chapterList

def run(self):

#是否触发错误

error=False

self.alert("开始处理章节内容")

if self.data['inputCharset'] is None or self.data['inputCharset'].strip()=='':

self.data['inputCharset']='gbk'

if self.data['outputCharset'] is None or self.data['outputCharset'].strip()=='':

self.data['outputCharset']='gbk'

if self.data['oldChapterTxtDir'] is None or self.data['oldChapterTxtDir'].strip()=='' :

self.alert('原始文件存放位置为空')

error=True

if self.data['newChapterTxtDir'] is None or self.data['newChapterTxtDir'].strip()=='':

self.data['newChapterTxtDir']=self.data['oldChapterTxtDir']

if os.path.exists(unicode(self.data['newChapterTxtDir'])) ==False:

os.makedirs(unicode(self.data['newChapterTxtDir']))

i=0

vol=''

volname=''

tmpVolName=''

currentNum=0

self.emit(QtCore.SIGNAL("setProcegressBar(int)"),len(self.chapterList))

if self.data['chapterTxtRegx'] is None:

regx=u""

for x in self.data['chapterTxtRegx'].split("\n"):

#print x

try:

re.compile(x)

except:

self.alert(unicode('内容处理正则表达式[
%s ]部分不正确'%(x)))

error=True

#self.alert('开始处理')

if error==False:

for x in self.chapterList:

while self.isWait:

self.sleep(1)

#self.wait(1)#使用wait的时候控制台会有输出

currentNum+=1

#self.alert(x['chapterName'])

#return

filename= self.data['oldChapterTxtDir']+'/'+x['filename']+self.data['oldChapterTxtExt']

if x['volName']!=tmpVolName:

chapterCount=1

i+=1

vol='卷 '+str(i)+'
'+x['volName']

if i>1:

self.alert(unicode('<strong><span style="color: red;">处理(%s)完毕!</span><strong>'%(str(i-1).zfill(2)+'卷
'+tmpVolName)))

tmpVolName=x['volName']

#volname=x['volName'].replace(u':',u'-')#必须去掉:否则可能出现文件名被截断的情况

self.alert(unicode('开始处理处理:%s……'%(str(i).zfill(2)+'卷
'+volname)))

else:

chapterCount+=1

if os.path.isfile(unicode(filename)):

content=open(unicode(filename)).read().decode(self.data['inputCharset']).encode('utf-8')

for regxSub in self.data['chapterTxtRegx'].split("\n"):

content=re.sub(regxSub,'
',content)

#去掉document.write('

content=re.sub("\s*document\.write\s*\(\s*['|\"]\s*",
'',content)

#去掉");这种标签

content=re.sub("\s*['|\"]\s*\)\s*[;]?", "\r\n\r\n",content)

content=content.replace("\n","\r\n\r\n").replace("\");","\r\n\r\n")

content="\r\n\r\n "+content.replace("')",'').replace("

","\r\n\r\n")[4:]

#去掉多余的类似的标签

content=re.sub("<[a-z\s/]+>",
'',content)

if len(x['chapterName'].split(' '))>1:

chapter=x['chapterName'][x['chapterName'].index(' ')+1:]

else:

chapter=x['chapterName']

if len(x['volName'].split(' '))==2:

volname=x['volName'][x['volName'].index(' ')+1:]

else:

volname=x['volName']

#递归判断去除章节名前的数字

try:

int(chapter[0:4])

chapter=chapter[4:]

except:

try:

int(chapter[0:3])

chapter=chapter[3:]

except:

try:

int(chapter[0:2])

chapter=chapter[2:]

except:

try:

int(chapter[0:1])

chapter=chapter[1:]

except:

chapter=chapter

chapter=' 第'+str(chapterCount).zfill(3)+'章 '+chapter

filename=self.data['newChapterTxtDir']+'/第'+str(i).zfill(2)+'卷 '+volname+chapter+'.txt'

#self.alert(filename)

#return

filename=filename.strip()

try:

f=open(unicode(filename),'wb')

except:

self.alert(unicode('写入文件“%s”错误'%(filename)))

#self.alert('写入文件“%s”错误'%(filename))

'''try:

f.write(content.decode('utf-8').encode(self.data['outputCharset']))

except:

self.alert(unicode('写入文件(%s)失败!'%(filename)))

f.close()'''

f.write(content.decode('utf-8').encode(self.data['outputCharset']))

f.close()

#del content

#self.window.umd_progressBar.setValue(currentNum)

self.emit(QtCore.SIGNAL("updateProcegressBar(int)"),currentNum)

#self.window.umd_textEditMessageOutPut.append(unicode('处理(%s)完毕!'%(str(i).zfill(2)+'卷 '+volname+chapter)))

self.alert(unicode('处理文件(%s)完毕!'%(str(i).zfill(2)+'卷 '+volname+chapter)))

else:

self.alert(unicode('处理失败: 章节文件不存在'))

#self.alert('章节列表文件处理完毕')

#import ctypes

#libc = ctypes.CDLL('libc.so.6')

#libc.printf('Hello world!')

def alert(self, txt):

#self.window.updateStatuBar(txt)

self.emit(QtCore.SIGNAL("msg(QString)"),QtCore.QString(unicode(txt)))

return

class umd_MainWindow(QtGui.QMainWindow, Ui_umd_MainWindow):

"""

Class documentation goes here.

"""

def __init__(self, parent = None):

"""

Constructor

"""

QtGui.QMainWindow.__init__(self, parent)

try:

#某些版本必须使用reload(sys)来重新载入sys模块才包含有setdefaultencoding方法

reload(sys)

sys.setdefaultencoding('utf-8')

except:

sys.setappdefaultencoding('utf-8')

#self.bmpdir=os.path.join(os.path.dirname(os.path.abspath(sys.argv[0])), 'res')

self.setupUi(self)

#以下为窗口自动居中

screen = QtGui.QDesktopWidget().screenGeometry()

size = self.geometry()

self.move((screen.width()-size.width())/2, (screen.height()-size.height())/2)

#设置按钮为隐藏

#self.umd_pushButton_pause.setHidden(True)

self.umd_pushButton_pause.hide()

self.umd_pushButton_Resume.hide()

self.umd_pushButton_Stop.hide()

#载入上一次的配置文件

self.cfg=DictIni(os.getcwd()+'/ebook.ini',encoding= 'utf-8')

if len(self.cfg.recentSetting)>0:

self.loadRecentSetting()

#以下开始设置进度条

self.umd_progressBar.setRange(0, 100)

self.umd_progressBar.setValue(0)

#self.showFullScreen()

#self.showNormal()

#self.isMinimized()

#创建一个文件处理线程

self.thread = ebookParseWorker(parent)

#线程退出

self.connect(self.thread, QtCore.SIGNAL("finished()"), self.finished)

self.connect(self.thread, QtCore.SIGNAL("terminated()"), self.finished)

#线程输出

self.connect(self.thread, QtCore.SIGNAL("msg(QString)"), self.message)

self.connect(self.thread, QtCore.SIGNAL("updateProcegressBar(int)"), self.updateProcegressBar)

self.connect(self.thread, QtCore.SIGNAL("setProcegressBar(int)"), self.setProcegressBar)

#open('./log.txt','wb').write(self.bmpdir)

#线程定义结束

pass

def loadRecentSetting(self):

self.umd_lineEditChapterTxtNew.setText(self.cfg.recentSetting.newTxtDir.decode('utf-8'))

self.umd_textEditChapterContentRegx.setPlainText(self.cfg.recentSetting.chapterContentRegx.decode('utf-8'))

self.umd_lineEditChapterJs.setText(self.cfg.recentSetting.chapterJs.decode('utf-8'))

self.umd_lineEditChapterRegx.setText(self.cfg.recentSetting.chapterRegx.decode('utf-8'))

self.umd_lineEditChapterTxtExt.setText(self.cfg.recentSetting.txtExt.decode('utf-8'))

self.umd_lineEditChapterTxtOld.setText(self.cfg.recentSetting.oldTxtDir.decode('utf-8'))

inputCharsetIndex=self.umd_comboBoxInputCharset.findText(self.cfg.recentSetting.inputCharset.decode('utf-8'))

self.umd_comboBoxInputCharset.setCurrentIndex(inputCharsetIndex)

outputCharsetIndex=self.umd_comboBoxOutputCharset.findText(self.cfg.recentSetting.outputCharset.decode('utf-8'))

self.umd_comboBoxOutputCharset.setCurrentIndex(outputCharsetIndex)

umdChapterContentRegx=str(self.umd_textEditChapterContentRegx.toPlainText().toUtf8())

#self.umd_lineEditChapterJs.setText(umd_textEditChapterContentRegx)

umdChapterRegx=str(self.umd_lineEditChapterRegx.text().toUtf8())

umdChapterTxtExt=str(self.umd_lineEditChapterTxtExt.text().toUtf8())

umdChapterTxtOld=str(self.umd_lineEditChapterTxtOld.text().toUtf8())

umdChapterTxtNew=str(self.umd_lineEditChapterTxtNew.text().toUtf8())

umdChapterJs=str(self.umd_lineEditChapterJs.text().toUtf8())

#原始文件编码

umdInputCharset=str(self.umd_comboBoxInputCharset.currentText().toUtf8())

#新文件编码

umdOutputCharset=self.umd_comboBoxOutputCharset.currentText().toUtf8().__str__()

pass

def closeEvent(self, event):

reply = QtGui.QMessageBox.question(self, QtGui.QApplication.translate("umd_MainWindow", "消息", None, QtGui.QApplication.UnicodeUTF8),

QtGui.QApplication.translate("umd_MainWindow", "确认关闭窗口?", None, QtGui.QApplication.UnicodeUTF8), QtGui.QMessageBox.Yes, QtGui.QMessageBox.No)

if reply == QtGui.QMessageBox.Yes:

event.accept()

else:

event.ignore()

def alert(self, txt):

response = False

# buttons texts

Close = QtGui.QApplication.translate("umd_MainWindow", "关闭", None, QtGui.QApplication.UnicodeUTF8)

#RELOAD='reload'

#CANCEL='cancel'

message = QtGui.QMessageBox(self)

message.setText(QtGui.QApplication.translate("umd_MainWindow",txt, None, QtGui.QApplication.UnicodeUTF8),)

message.setWindowTitle(QtGui.QApplication.translate("umd_MainWindow", "消息", None, QtGui.QApplication.UnicodeUTF8),)

message.setIcon(QtGui.QMessageBox.Warning)

message.addButton(Close, QtGui.QMessageBox.AcceptRole)

#message.addButton(RELOAD, QtGui.QMessageBox.DestructiveRole)

#message.addButton(CANCEL, QtGui.QMessageBox.RejectRole)

#message.setDetailedText(txt)

message.exec_()

response = message.clickedButton().text()

'''

if response == SAVE:

fd = QtGui.QFileDialog(self)

newfile = fd.getSaveFileName()

if newfile:

s = codecs.open(newfile,'w','utf-8')

s.write(unicode(self.ui.editor_window.toPlainText()))

s.close()

self.ui.button_save.setEnabled(False)

# new file, remove old and add the new one to the watcher

if self.filename and str(newfile) != str(self.filename):

self.watcher.removePath(self.filename)

self.watcher.addPath(newfile)

self.filename = newfile

# reload the text in the editor

elif response == RELOAD:

s = codecs.open(self.filename,'r','utf-8').read()

self.ui.editor_window.setPlainText(s)

self.ui.button_save.setEnabled(False)

'''

@QtCore.pyqtSignature("")

def on_umd_toolButtonChapterTxtNew_clicked(self):

"""

Slot documentation goes here.

"""

#raise NotImplementedError

dlg=QtGui.QFileDialog(self)

oldDir=unicode(self.umd_lineEditChapterTxtNew.text())

if oldDir.strip()=='':

oldDir=os.getcwd()

self.chapterTxtDirOld = dlg.getExistingDirectory(self, QtGui.QApplication.translate("umd_MainWindow", "请选择处理后的TXT文件的位置", None, QtGui.QApplication.UnicodeUTF8), oldDir)

if os.path.isdir(self.chapterTxtDirOld):

self.umd_lineEditChapterTxtNew.setText(self.chapterTxtDirOld)

def setProcegressBar(self, i):

self.umd_progressBar.setRange(0, i)

pass

def updateProcegressBar(self, i):

self.umd_progressBar.setValue(i)

pass

def message(self, txt):

self.umd_textEditMessageOutPut.append(txt)

def finished(self):

#print '处理完毕'

self.umd_textEditMessageOutPut.append(unicode('所有内容处理完毕'))

#处理完毕,隐藏暂停和停止按钮

self.umd_pushButton_pause.hide()

self.umd_pushButton_Resume.hide()

self.umd_pushButton_Stop.hide()

self.umd_pushButton_submit.show()

self.umd_pushButton_close.show()

#self.umd_plainTextEditMessageOutPut.appendPlainText(unicode('所有内容处理完毕'))

@QtCore.pyqtSignature("")

def on_umd_pushButton_Resume_clicked(self):

self.thread.isWait=False

self.umd_pushButton_pause.show()

self.umd_pushButton_Resume.hide()

self.umd_pushButton_Stop.show()

pass

@QtCore.pyqtSignature("")

def on_umd_pushButton_Stop_clicked(self):

self.thread.terminate()

self.umd_pushButton_submit.show()

self.umd_pushButton_close.show()

self.umd_pushButton_pause.hide()

self.umd_pushButton_Resume.hide()

self.umd_pushButton_Stop.hide()

@QtCore.pyqtSignature("")

def on_umd_pushButton_pause_clicked(self):

self.thread.isWait=True

#隐藏按钮

self.umd_pushButton_pause.hide()

self.umd_pushButton_Resume.show()

self.umd_pushButton_Stop.show()

pass

@QtCore.pyqtSignature("")

def on_umd_toolButtonChapterTxtOld_clicked(self):

"""

Slot documentation goes here.

"""

dlg=QtGui.QFileDialog(self)

oldDir=unicode(self.umd_lineEditChapterTxtOld.text())

if oldDir.strip()=='':

oldDir=os.getcwd()

self.chapterTxtDirOld = dlg.getExistingDirectory(self, QtGui.QApplication.translate("umd_MainWindow", "请选择CHM导出的TXT文件的位置", None, QtGui.QApplication.UnicodeUTF8), oldDir)

if os.path.isdir(self.chapterTxtDirOld):

self.umd_lineEditChapterTxtOld.setText(self.chapterTxtDirOld)

@QtCore.pyqtSignature("")

def on_umd_toolButtonChapterJs_clicked(self):

"""

Slot documentation goes here.

"""

dlg=QtGui.QFileDialog(self)

oldDir=unicode(self.umd_lineEditChapterJs.text())

if oldDir.strip()=='':

oldDir=os.getcwd()

self.chapterJsFilename = dlg.getOpenFileName(self, QtGui.QApplication.translate("umd_MainWindow", "请选择目录列表JS位置", None, QtGui.QApplication.UnicodeUTF8), oldDir,QtGui.QApplication.translate("umd_MainWindow",
"js文件(*.js);;文本文件(*.txt);;所有文件(*)",
None, QtGui.QApplication.UnicodeUTF8))

if os.path.isfile(self.chapterJsFilename):

dir=os.path.dirname(unicode(self.chapterJsFilename))

#对于从CHM中展开的电子书,一般保持这样的结构

if dir[-2:]=='js':

dir=dir[0:len(dir)-2]+'txt'

#self.alert(dir[-2:])

self.umd_lineEditChapterJs.setText(self.chapterJsFilename)

self.umd_lineEditChapterTxtOld.setText(dir)

@QtCore.pyqtSignature("")

def on_umd_pushButton_submit_clicked(self):

"""

Slot documentation goes here.

"""

#raise NotImplementedError

umdChapterContentRegx=str(self.umd_textEditChapterContentRegx.toPlainText().toUtf8())

#print umdChapterContentRegx

#self.umd_lineEditChapterJs.setText(umd_textEditChapterContentRegx)

umdChapterRegx=str(self.umd_lineEditChapterRegx.text().toUtf8())

umdChapterTxtExt=str(self.umd_lineEditChapterTxtExt.text().toUtf8())

umdChapterTxtOld=str(self.umd_lineEditChapterTxtOld.text().toUtf8())

umdChapterTxtNew=str(self.umd_lineEditChapterTxtNew.text().toUtf8())

umdChapterJs=str(self.umd_lineEditChapterJs.text().toUtf8())

#原始文件编码

umdInputCharset=str(self.umd_comboBoxInputCharset.currentText().toUtf8())

#新文件编码

umdOutputCharset=self.umd_comboBoxOutputCharset.currentText().toUtf8().__str__()

'''

>>>print type(self.umd_comboBoxInputCharset.currentText())

>>>

>>>print type(self.umd_comboBoxInputCharset.currentText().toUtf8())

>>>

>>>print str(self.umd_comboBoxInputCharset.currentText()).encode('utf-8')

>>>选择编码

>>>dir(self.umd_comboBoxInputCharset.currentText())

>>>['KeepEmptyParts', 'NormalizationForm', 'NormalizationForm_C', 'NormalizationForm_D', 'NormalizationForm_KC', 'NormalizationForm_KD', 'SectionCaseInsensitiveSeps', 'SectionDefault', 'SectionFlag', 'SectionFlags', 'SectionIncludeLeadingSep', 'SectionIncludeTrailingSep',
'SectionSkipEmpty', 'SkipEmptyParts', 'SplitBehavior', '__add__', '__class__', '__contains__', '__delattr__', '__dict__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__gt__', '__hash__', '__iadd__', '__imul__', '__init__',
'__le__', '__len__', '__lt__', '__module__', '__mul__', '__ne__', '__new__', '__radd__', '__reduce__', '__reduce_ex__', '__repr__', '__rmul__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'append', 'arg', 'at', 'capacity', 'chop',
'clear', 'compare', 'contains', 'count', 'endsWith', 'fill', 'fromAscii', 'fromLatin1', 'fromLocal8Bit', 'fromUtf8', 'indexOf', 'insert', 'isEmpty', 'isNull', 'isRightToLeft', 'isSimpleText', 'lastIndexOf', 'left', 'leftJustified', 'length', 'localeAwareCompare',
'mid', 'normalized', 'number', 'prepend', 'push_back', 'push_front', 'remove', 'repeated', 'replace', 'reserve', 'resize', 'right', 'rightJustified', 'section', 'setNum', 'simplified', 'size', 'split', 'squeeze', 'startsWith', 'toAscii', 'toCaseFolded', 'toDouble',
'toFloat', 'toInt', 'toLatin1', 'toLocal8Bit', 'toLong', 'toLongLong', 'toLower', 'toShort', 'toUInt', 'toULong', 'toULongLong', 'toUShort', 'toUpper', 'toUtf8', 'trimmed', 'truncate']

>>>self.umd_comboBoxInputCharset.currentText().__str__()

>>>选择编码

'''

#保存设置

self.cfg.recentSetting.oldTxtDir=umdChapterTxtOld

self.cfg.recentSetting.newTxtDir=umdChapterTxtNew

self.cfg.recentSetting.txtExt=umdChapterTxtExt

self.cfg.recentSetting.chapterJs=umdChapterJs

self.cfg.recentSetting.chapterRegx=umdChapterRegx

self.cfg.recentSetting.chapterContentRegx=umdChapterContentRegx

self.cfg.recentSetting.inputCharset=umdInputCharset

self.cfg.recentSetting.outputCharset=umdOutputCharset

self.cfg.save()

#开始操作

#self.alert(umdChapterContentRegx)

#重置进度条

self.umd_progressBar.setValue(0)

#重置状态窗口

self.umd_textEditMessageOutPut.clear()

#self.umd_plainTextEditMessageOutPut.clear()

'''self.thread.setVar('chmChapterRegx', unicode(umdChapterRegx))

self.thread.setVar('chmChapterJs', unicode(umdChapterJs))

self.thread.setVar('oldChapterTxtDir', unicode(umdChapterTxtOld))

self.thread.setVar('inputCharset', unicode(umdInputCharset))

self.thread.setVar('oldChapterTxtExt', unicode(umdChapterTxtExt))

self.thread.setVar('chapterTxtRegx', unicode(umdChapterContentRegx))

self.thread.setVar('newChapterTxtDir', unicode(umdChapterTxtNew))

self.thread.setVar('outputCharset', unicode(umdOutputCharset))'''

self.thread.setVar('chmChapterRegx', umdChapterRegx)

self.thread.setVar('chmChapterJs', umdChapterJs)

self.thread.setVar('oldChapterTxtDir', umdChapterTxtOld)

self.thread.setVar('inputCharset', umdInputCharset)

self.thread.setVar('oldChapterTxtExt', umdChapterTxtExt)

self.thread.setVar('chapterTxtRegx', umdChapterContentRegx)

self.thread.setVar('newChapterTxtDir', umdChapterTxtNew)

self.thread.setVar('outputCharset', umdOutputCharset)

#print self.thread.data

#开始执行

self.umd_pushButton_submit.setHidden(True)

self.umd_pushButton_close.hide()

#显示暂停和停止窗口

self.umd_pushButton_pause.show()

self.umd_pushButton_Stop.show()

#

self.thread.buildRegx()

self.thread.getChapterList()

self.thread.start()

@QtCore.pyqtSignature("")

def on_umd_pushButton_close_clicked(self):

self.close()

if __name__ == "__main__
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: