作为一个自动化测试人员,开发基本的应用桌面程序是必须的!最近在研究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. SQL Server查询所有的表名、字段名、注释

    SELECT 表名 then d.name else '' end, 表说明 then isnull(f.value,'') else '' end, 字段序号=a.colorder, 字段名=a.n ...

  2. 【c#】RabbitMQ学习文档(四)Routing(路由)

    (使用Net客户端) 在上一个教程中,我们构建了一个简单的日志系统,我们能够向许多消息接受者广播发送日志消息. 在本教程中,我们将为其添加一项功能 ,这个功能是我们将只订阅消息的一个子集成为可能. 例 ...

  3. windows下安装bpython方法 (新)

    刚开始学习python的时候使用的ipython解释器,挺好用的,后来发现bpython功能更强大,linux系统中安装基本没啥问题,不过在windows下安装倒是不容易啊.使用google搜了一下, ...

  4. .NET快速信息化系统开发框架 V3.2 -> WinForm“组织机构管理”界面组织机构权限管理采用新的界面,操作权限按模块进行展示

    对于某些大型的企业.信息系统,涉及的组织机构较多,模块多.操作权限也多,对用户或角色一一设置模块.操作权限等比较繁琐.我们可以直接对某一组织机构进行权限的设置,这样设置后,同一组织机构的用户就可以拥有 ...

  5. 痞子衡嵌入式:ARM Cortex-M文件那些事(5)- 映射文件(.map)

    大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家讲的是嵌入式开发里的map文件. 第四节课里,痞子衡给大家介绍了第一种output文件-relocatable文件,本文继续给大家讲projec ...

  6. 全网Star最多(近20k)的Spring Boot开源教程 2019 年要继续更新了!

    从2016年1月开始写博客,默默地更新<Spring Boot系列教程>,从无人问津到千万访问,作为一个独立站点(http://blog.didispace.com),相信只有那些跟我一样 ...

  7. web类协议脚本-飞机订票系统示例

    以下是LR自带的飞机订票系统的Demo,希望能帮助大家. Action() { int iRand; int iTmp; char *strTmpA; char *strTmpB; char *str ...

  8. PLSQL创建Oracle定时任务

    在使用oracle最匹配的工具plsql的时候,如果用plsql创建定时器呢?下面我简单介绍使用工具创建定时器的方法: 1.创建任务执行的存储过程,如名称为YxtestJob,向测试表中插入数据 cr ...

  9. Oracle游标的使用示例

    此文是使用Oracle游标的几种方式,for...in会自动打开游标,fetch...into需要手动打开游标,游标类似于一个只会往前移动的指针,每次指向数据集中的一行数据,通过游标可以打开数据集,也 ...

  10. .Net 接入CAS 遇到的坑

    关于CAS是个什么东西,就不多闲扯了,相信每个有过SSO经验的都听过CAS大名,百度百科地址: https://baike.baidu.com/item/CAS/1329561?fr=aladdin ...