作为一个自动化测试人员,开发基本的应用桌面程序是必须的!最近在研究wxpython相关知识,目前看到多线程一块,发现官方文档介绍说:"在线程中不能修改修改窗口属性!",但是实际情况是:最近在做一个翻墙的简单APP。我开了2个线程一个线程用于显示设置进度(用的是第三方host,所以要下载host再覆盖本地host) ,一个线程处理下载任务,发现第一个线程中动态的设置self.gauge(value)可以生效,并没用到wx.CallAfter!! 需要注意的是,wxpython一次只能处理一个事件,避免同时在线程中启用用wx.CallAfter,这样wxpython还是一个一个去执行CallAfter传递函数。即:启用N个线程,N-1个用来干事情(不要在线程种使用CallAfter),第N个线程调用CallAfter通知主线程更新界面。上面说过了本人尝试了在线程中直接更改主窗口控件(不知道是否出现问题)。是可行的!但是,还是建议按照官方说法利用wx.CallAfter,以免发生异常崩溃。

wxpython多线程应用的常景:对于一些复杂任务的处理(比如下载若干文件),如果把这些代码全部放在主线程中,等你触发了这个事件后,应用程序会卡死,而且也触发不了其他时间,几乎处于一个假死状态(虽然他还活着...),这样的程序别说给别人用了,自己用都会崩溃....,所以就用到多线程,触发了下载事件后,在线程中完成任务,主线程干干嘛干嘛,但是要给一下提示给窗口程序,比如触发下载按钮时,主程序有"下载中..."等字样,下载完成后,线程通知窗口程序更新状态为"下载完成...",这样的交互至少是友善的。

wxpython多线程的使用方法:wxpython开发者建议的是使用wx.CallAfter+PubSub。CallAfter负者推送时间给主程序,PubSub实现wxPython应用程序与其他线程进行通信。

其实在wx.CallAfter中直接传一个主线程的方法,更简单!但是既然官方这样说,我们就这样用!!好吧我们来一个官方的例子,来看看wxpython如何使用的~

import time
import wx
from threading import Thread
from wx.lib.pubsub import Publisher ########################################################################
class TestThread(Thread):
"""Test Worker Thread Class.""" #----------------------------------------------------------------------
def __init__(self):
"""Init Worker Thread Class."""
Thread.__init__(self)
self.start() # start the thread #----------------------------------------------------------------------
def run(self):
"""Run Worker Thread."""
# This is the code executing in the new thread.
for i in range(6):
time.sleep(10)
wx.CallAfter(self.postTime, i)
time.sleep(5)
wx.CallAfter(Publisher().sendMessage, "update", "Thread finished!") #----------------------------------------------------------------------
def postTime(self, amt):
"""
Send time to GUI
"""
amtOfTime = (amt + 1) * 10
Publisher().sendMessage("update", amtOfTime) ########################################################################
class MyForm(wx.Frame): #----------------------------------------------------------------------
def __init__(self):
wx.Frame.__init__(self, None, wx.ID_ANY, "Tutorial") # Add a panel so it looks the correct on all platforms
panel = wx.Panel(self, wx.ID_ANY)
self.displayLbl = wx.StaticText(panel, label="Amount of time since thread started goes here")
self.btn = btn = wx.Button(panel, label="Start Thread") btn.Bind(wx.EVT_BUTTON, self.onButton) sizer = wx.BoxSizer(wx.VERTICAL)
sizer.Add(self.displayLbl, 0, wx.ALL|wx.CENTER, 5)
sizer.Add(btn, 0, wx.ALL|wx.CENTER, 5)
panel.SetSizer(sizer) # create a pubsub receiver
Publisher().subscribe(self.updateDisplay, "update") #----------------------------------------------------------------------
def onButton(self, event):
"""
Runs the thread
"""
TestThread()
self.displayLbl.SetLabel("Thread started!")
btn = event.GetEventObject()
btn.Disable() #----------------------------------------------------------------------
def updateDisplay(self, msg):
"""
Receives data from thread and updates the display
"""
t = msg.data
if isinstance(t, int):
self.displayLbl.SetLabel("Time since thread started: %s seconds" % t)
else:
self.displayLbl.SetLabel("%s" % t)
self.btn.Enable() #----------------------------------------------------------------------
# Run the program
if __name__ == "__main__":
app = wx.PySimpleApp()
frame = MyForm().Show()
app.MainLoop()

上述代码我们随便搜索下wxpython多线程的应用多会举官方这个例子,可能是版本的问题(本人用的是wx-2.8),第一句就给来个错,网上search一下提出这个Publisher这个moudle不存在的问题是普遍的,但是没有相应的说法,现在就针对这个经典的wxpython程序剖析一下。这段代码本身是简单的,由于版本的问题可能出现如下问题。

1.ImportError: cannot import name Publisher

出现这个错误是正常的,我们进入wx.lib.pubsub这个模块发现并没有Publisher这个类,但是我们在wx.lib.pubsub这个模块下面的pub模块发现了Publisher的影子,原来在2.8版本时已经将这个类私有化了,见126行,_publisher = _Publisher(),同时将Publisher的subscribe与sendMessage复制给了subscribe与sendMessage变量见(128,131)行。所以我们这样引入头:from wx.lib.pubsub import pub,同时将所有的Publisher()改为pub。
2.TypeError: sendMessage() takes exactly 2 arguments (3 given)

经过1的修改,以为大功告成,运行依然报错崩溃。出现这个问题大多数人如果硬找问题原因很难找的,我们debug进出,发现他实例化的是"C:\Python27\Lib\site-packages\wx-2.8-msw-unicode\wx\lib\pubsub\core\kwargs\publisher.py"这个模块下的Publisher类,仔细一看sendMessage方法果然第二个参数应该传个字典类型的所有我们将本程序24,32,71行改为wx.CallAfter(pub.sendMessage, "update", msg="Thread finished!"),pub.sendMessage("update", msg=amtOfTime),t = msg。运行一下没问题~~注意sendMessage的键值(这里是msg)与subscribe监听方法种的接收参数(这里是msg)要相同,看源码其实就是msgKwargs这个字典参数来传递值的。

其实,这段代码没有问题的。我们注意到”C:\Python27\Lib\site-packages\wx-2.8-msw-unicode\wx\lib\pubsub\core\__init__.py" 的43行,其实core这个模块对于Publisher这个类的加载是动态的。我们进入policies.py这个模块第10行,发现msgDataProtocol = 'kwargs',原来如此...我们知道core模块下面有2个包一个是arg1,一个是kwargs,我们观察这2个包publisher模块下Publisher类的sendMessage方法是不一样的。原来我们这端代码用的是arg1下的这个Publisher类,好吧,我们将policies.py的第10行改为msgDataProtocol ='arg1',还原代码运行正确!!kwargs与arg1不同点是kwargs可以传递多个参数给主程序(**kwargs),而arg1只能是传递一个参数。

经过以上简单的论述,我们知道了wxpython是通过wx.CallAfter给主程序推入事件,通过PubSub与主程序传递数据。关于wxpython多线程的简单理解就是这样了,希望能提供帮助。

关于wxpython多线程研究包括(import Publisher等错误研究)的更多相关文章

  1. 关于wxpython多线程研究包括(import Publisher错误研究)

    作为一个自动化测试人员,开发基本的应用桌面程序是必须的!最近在研究wxpython相关知识,目前看到多线程一块,发现官方文档介绍说:"在线程中不能修改修改窗口属性!",但是实际情况 ...

  2. Android开发-解决 AIDL 中找不到couldn't find import for class错误

    最近在使用AIDL做IPC的时候,在处理复杂的数据类型的时候,编译器总是报couldn't find import for class错误,所以在这里总结下AIDL使用的时候的一些注意事项,希望对你能 ...

  3. 解决nextjs部署到now上之后出现的“Unable to import module 'now__launcher'”错误

    解决nextjs部署到now上之后出现的“Unable to import module 'now__launcher'”错误 这个错误是由于在next.config.js中直接引用了withLess ...

  4. c#中多线程同步Lock(锁)的研究以及跨线程UI的操作

    本文只针对C#中,多线程同步所用到的锁(lock)作为研究对象.由于想更直观的显示结果,所以,在做demo的时候,就把多线程通过事件操作UI的代码也写了出来,留作备忘和分享吧. 其实多线程的同步,使用 ...

  5. wxpython多线程通信的应用-实现边录音边绘制音谱图

    #!bin/bash/python # -*- coding=utf-8 -*- from __future__ import division import threading import wx ...

  6. wxpython多线程间通信

    #!bin/bash/python # -*- coding=utf-8 -*- import time import wx from threading import Thread from wx. ...

  7. c#中多线程同步Lock(锁)的研究以及跨线程UI的操作 (转)

    https://www.cnblogs.com/tommyheng/p/4104552.html 本文只针对C#中,多线程同步所用到的锁(lock)作为研究对象.由于想更直观的显示结果,所以,在做de ...

  8. C# 多线程 Parallel.ForEach 和 ForEach 效率问题研究及理解

    from:https://blog.csdn.net/li315171406/article/details/78450534 最近要做一个大数据dataTable循环操作,开始发现 运用foreac ...

  9. python ssh弱口令爆破多线程脚本及遇到的一些错误与问题

    练习写了个SSH弱口令爆破多线程脚本,遇到的问题 1.一开始想import pexpect 中的pxssh 然而却一直该有错误, ImportError: cannot import name spa ...

随机推荐

  1. opensuse使用zypper安装软件

    安装软件(opensuse) opensuse 通过zypper可以方便的进行软件管理,类似centos的yum 软件. 命令参考 软件包操作 搜索软件 zypper search package 安 ...

  2. PC逆向之代码还原技术,第五讲汇编中乘法的代码还原

    目录 PC逆向之代码还原技术,第五讲汇编中乘法的代码还原 一丶简介乘法指令 1.乘法指令 2.代码还原注意问题 二丶乘法的汇编代码产生的格式 1.高级代码观看 2.乘法的汇编代码还原. 三丶乘法总结 ...

  3. 汇编实现: C库常见函数,串操作指令作用

    目录 汇编实现: C库常见函数 一丶汇编实现Strncpy拷贝函数 二丶loads实现Strlen操作. 三丶stos的作用 汇编实现: C库常见函数 一丶汇编实现Strncpy拷贝函数 void _ ...

  4. selenium和webdriver区别

    接触selenium大概半年时间了.从开始的预研,简单的写个流程到后期的自动化框架的开发,因为本人不属于代码方面的大牛,一直的边研究边做.逐步深入学习.近期发现自己对本身selenium的发展还存在困 ...

  5. Node.js 进程平滑离场剖析

    本文由云+社区发表 作者:草小灰 使用 Node.js 搭建 HTTP Server 已是司空见惯的事.在生产环境中,Node 进程平滑重启直接关系到服务的可靠性,它的重要性不容我们忽视.既然是平滑重 ...

  6. 原型模式 prototype 创建型 设计模式(七)

    原型模式  prototype 意图 用原型实例指定需要创建的对象的类型,然后使用复制这个原型对象的方法创建出更多同类型的对象   显然,原型模式就是给出一个对象,然后克隆一个或者更多个对象 小时候看 ...

  7. Mac homebrew-1.5以后安装php扩展的方法

    一.以前Mac安装php及php扩展的方式 用Mac的童鞋都知道,我们以前都是用brew install php70,brew install php71 这样来安装php的,用brew instal ...

  8. Perl线程队列:Thread::Queue

    (Thread::Queue)队列数据结构(FIFO)是线程安全的,它保证了某些线程从一端写入数据,另一些线程从另一端读取数据.只要队列已经满了,写入操作就自动被阻塞直到有空间支持写操作,只要队列空了 ...

  9. eclipse部署Tomcat9

    1.下载 下载地址https://tomcat.apache.org/download-90.cgi  2.解压文件  3.运行bin-->startup.bat文件,若界面如下图,则成功 4. ...

  10. Excel读写

    http://www.cnblogs.com/mingforyou/archive/2013/08/26/3282922.html 读Excel代码如下: import java.io.File;im ...