Python / wxPython 学习笔记 – Day 2 多线程 / 文本编码

转到Ubuntu学习已经很长时间,另外在VirtualBox虚拟机中安装了WinXP,以检测跨平台的问题。
关于多线程,我想实现的功能具体是:子线程运算,更新主线程进度条; 子线程调用外部进程获取返回值,更新主线程进度条

文本编码问题

我的第一个wxpython程序的第一个版本中,我为了在windows系统下正确显示中文,大量采用了

.encode('gbk')

的输出方式,然而这种方式在默认编码为UTF-8的Linux系统下无法正常显示。
so how to solve it?
下面是我的解决方法:
1, 在win下安装wxpython的unicode版本,直接传unicode字符串给wxpython相关方法,即可显示中文
2, 调用外部命令等必须严格按照系统编码的时候,可以采用下面的编码方式(当然,先import sys):

.encode(sys.getfilesystemencoding())

这样即可达到相当好的跨平台兼容性:)

多线程问题

先来看第一个程序:子线程运算,更新主线程进度条
(程序目的是计算MD5)

import threading, hashlib, os
class TRun(threading.Thread):
    def __init__(self, caller):
        threading.Thread.__init__(self)
        self.caller = caller
    def run(self):
        global file
        m1 = hashlib.md5()
        f = open(file,'rb')
        f1 = os.stat(file)
        size = f1.st_size
        now = 9728000
        bytes = f.read(9728000)
        while(bytes != ''):
            m1.update(bytes)
            i=now*100/size
            if(i>100): i=100
            wx.CallAfter(self.caller.updateProgress1, i)
            bytes = f.read(9728000)
            now+=9728000
        f.close()
#然后在窗体Frame类里加入如下方法:
    def updateProgress1(self, i):
        self.flag = self.progress.Update(i)
#调用TRun类的方法
self.progress = wx.ProgressDialog(u"标题...", u"内容, 请稍候…", 100,  style=wx.PD_AUTO_HIDE)
self.t = TRun(self)
self.t.setDaemon(True)
self.t.start()
#self.t.join()  #如果需要等待子线程运行完再继续,去掉此行的注释

稍作解释:
1, wx.ProgressDialog进度条的wx.PD_AUTO_HIDE属性,作用是进度条满格后自动隐藏
2, wx.CallAfter方法的作用是让主线程执行函数(子线程是无权修改主线程界面元素的,包括进度条)

下面则是调用外部程序(以par2为例),获取返回值并修改主程序进度条的功能实现:

class TRun2(threading.Thread):
    def __init__(self, caller):
        threading.Thread.__init__(self)
        self.caller = caller
    def run(self):
        global file
        ans=''
        arg='par2 c -r3 \"'+file.encode(sys.getfilesystemencoding())+'.par2\" \"'+file.encode(sys.getfilesystemencoding())+'\"'
        import subprocess
        p = subprocess.Popen(args=arg,stdout=subprocess.PIPE, shell=True)
        r1 = re.compile('Constructing[:\s]*([\d\.]+)%')
        r2 = re.compile('Processing[:\s]*([\d\.]+)%')
        r1yes = False
        while p.poll()==None:
            ans+=p.stdout.read(100)
            if not r1yes:
                k = r1.findall(ans)
                k2 = r2.findall(ans)
                if len(k2)>0:
                    r1yes = True
                    time.sleep(0.3)
            else:
                k = r2.findall(ans)
            if len(k)>0:
                wx.CallAfter(self.caller.updateProgress1, int(float(k[-1])))
            time.sleep(0.01)
#其他部分/调用方法与上例相同

下面仍然做一些解释:
1, 使用time.sleep(n)函数作用为延迟n秒(类似QBASIC的SLEEP)
2, 调用外部进程使用了subprocess.Popen()函数,以PIPE的方式获取stdout返回值,shell参数的意义是使用shell语法解析外部命令。
如果不需要使用shell,则arg需要修改为

arg=['par2','c','-r3',file.encode(sys.getfilesystemencoding())+'.par2',file.encode(sys.getfilesystemencoding())]
#将参数作为列表元素传入

3, 获取进度采用了正则表达式匹配,因为par2过程主要是constructing和processing耗时,因此让进度条走两次。此处我给的方法只是”可行“而已,不一定很好

参考资料:补充中

14 thoughts on “Python / wxPython 学习笔记 – Day 2 多线程 / 文本编码”

  1. 为啥用 wxPython,用 pygtk 不好么,我看到用 pygtk 的比较多点=,=

  2. 相识在于缘,相知在于诚,有老朋友的时候,能结识一些您这样新好朋友感到荣幸。

Leave a Reply

Your email address will not be published. Required fields are marked *

QR Code Business Card