python - 在 wxPython 中使用多线程

标签 python multithreading wxpython

我正在编写一个wxpython程序。 如果您在程序中打开一个文件,它会计算文件中的行数并将其显示在 staticText 小部件中。

相关代码如下:

类框架

def on_select_file(self, event):
    '''Event handler for selecting file'''
    filepath = getFile()  # This is a seperate method which asks the user to select a file and returns the path
    threading.Thread(target = methods.count_lines, args = (filepath, self.staticText)).start()

方法.py

def count_lines(filepath, staticText):
    with open(filepath) as f:
        for i, _ in enumerate(f): pass
    staticText.SetLabel(str(i+1))

我正在处理的大多数文件都非常大(3-4 GB),大约有 2500 万行。因此,如果我打开一个大文件,则需要几十秒的时间来计数并显示编号。的线路。但是,如果我选择一个大文件,并且在更新 staticText 小部件之前,打开另一个较小的文件,staticText 小部件会显示新的计数,但一段时间后会显示前一个文件的计数。我理解这是因为前一个线程仍在运行并在结束后更新了小部件。

我尝试通过将标志变量作为参数传递给计数器函数来解决这个问题,以检查小部件是否已更新。然而它似乎不起作用。还有其他方法可以避免这种情况吗?

最佳答案

本质上,创建一个包含当前行计数作为成员的自定义事件类型,并在工作线程中使用 wx.PostEvent() 定期将该类型的事件发布到包含静态文本小部件的类。然后,当主线程恢复并处理其事件循环时,您可以使用接收到的事件报告的行数来设置文本字符串。

这样的事情应该有效:

import time
from threading import *
import wx
import os.path

EVT_LINE_NUMBER_UPDATE_ID = wx.NewId()

class LineNumberUpdateEvent(wx.PyEvent):
    def __init__(self, lineNum):
        wx.PyEvent.__init__(self)
        self.SetEventType(EVT_LINE_NUMBER_UPDATE_ID)
        self.lineNumber = lineNum

class WorkerThread(Thread):
    def __init__(self, notify_window, filename):
        Thread.__init__(self)
        self._notify_window = notify_window
        self._filename = filename
        self.start()

    def run(self):
        with open(this._filename,"r") as file:
            count = 0;
            for line in file:
                 count++
                 if count % 50 == 0: # post an event every 50 lines
                     wx.PostEvent(self._notify_window, LineNumberUpdateEvent(count))
            wx.PostEvent(self._notify_window, LineNumberUpdateEvent(count)) # last event

class MainFrame(wx.Frame):
    def __init__(self, parent, id, filename):
        wx.Frame.__init__(self, parent, id, 'Threaded File Loader')
        self.status = wx.StaticText(self, -1, '', pos=(0,100))
        self.Bind(EVT_LINE_NUMBER_UPDATE_ID, self.OnLineNumberUpdate)
        if (os.path.isfile(filename))
            self.worker = WorkerThread(self,filename)

    def OnLineNumberUpdate(self, event):
        self.status.SetLabel(str(event.lineNumber))

这是根据 wx Wiki 上发布的示例改编的:

http://wiki.wxpython.org/LongRunningTasks

关于python - 在 wxPython 中使用多线程,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25301052/

相关文章:

php - python调用命令问题

c# - 在 C# 控制台应用程序中使用线程概念并行执行超过 2 个 Dtsx 包

windows-10 - 在 Windows 10 上绑定(bind)一些全局热键失败

python - Pyinstaller:创建具有多个依赖项的可执行文件 - "TypeError"

python - 如何拆分字符串中的两个项目?

python - 作为服务让 PubNub 订阅者保持事件状态 (Python SDK)

java - 在同一实例上使用同步方法锁定

python - 为什么这不起作用(wxpython/颜色对话框)

python - Flask 请求语法错误的问题

c# - 如何通过for循环条件停止多线程启动