线程记录到 TextCtrl

Thread Logging to TextCtrl

我正在尝试将线程中的值打印到在不同 class 中定义的 TextCtrl window。代码 posted 是精简版,它将在后台线程中增加一个值,然后尝试将其打印到 TextCtrl window.

我尝试过使用 pubsub,但找不到与我的代码足够接近的示例 "integrate"。

更新

我已将我的主题添加到它自己的 class 中,但现在出现错误。

如何使用 post 事件将数据发送到另一个 class 中的 textCtrl 框?

import wx 
import time
import threading

GlobalVar = False

#draws the GUI
class Mywin(wx.Frame): 
    def __init__(self, parent, title): 
    #Frame
       super(Mywin, self).__init__(parent, title = title,size = (500,300))  
       panel = wx.Panel(self) 
    #Constant stream toggle Button  
       self.tbtn =wx.ToggleButton(self, label="Constant Stream", pos=(20, 90))
       self.tbtn.Bind(wx.EVT_TOGGLEBUTTON, self.OnToggle)
    #Text window  
       self.logger = wx.TextCtrl(self, pos=(150,0), size=(400,100), style=wx.TE_MULTILINE | wx.TE_READONLY)
    #Draws and laysout the GUI
       panel.Layout()
       self.Centre() 
       self.Show() 
       self.Fit()

#=====================================================================
    def OnToggle(self,event):  #Toggle on, start background stream
        state = event.GetEventObject().GetValue()
        global GlobalVar

        if state == True:
            GlobalVar = True
            Stream.start()
            event.GetEventObject().SetLabel("Streaming")

        else:
            GlobalVar = False
            event.GetEventObject().SetLabel("Constant Stream")

class StreamThread(threading.Thread):
    def __init__(self, threadID, name):
        threading.Thread.__init__(self)
        self.threadID = threadID
        self.name = name

    def run(self):
        global GlobalVar
        IncrementMe = 0
        while GlobalVar == True:
            wx.PostEvent(Mywin.logger.AppendText(str(IncrementMe)))
            print(IncrementMe)
            time.sleep(1)
            IncrementMe = IncrementMe + 1

Stream = StreamThread(1, "Stream_Thread")
Stream.daemon = True

app = wx.App() 
Mywin(None,  'Incrementer') 
app.MainLoop()
del app

为了让这个工作正常,因为你已经接受了一个全局变量,只需将 logger 设为全局变量,而不是 self.logger
注意 self.logger.AppendText(IncrementMe) 必须变成 logger.AppendText(str(IncrementMe)),因为附加 int 会让你很伤心。
理想情况下,您应该重写它以将 thread 作为 Class,然后您可以使用 wx.PostEvent 通过绑定到事件来触发 MyWin 中的操作。
参见:https://wxpython.org/Phoenix/docs/html/events_overview.html https://www.blog.pythonlibrary.org/2010/05/22/wxpython-and-threads/

编辑: 这是一个 pubsub 脚本,希望它能为您指明正确的方向。

from threading import Thread
import wx
from wx.lib.pubsub import pub
import time
class WorkThread(Thread):

    def __init__(self):
        """Init Worker Thread Class."""
        Thread.__init__(self)
        self.stop_work_thread = 0
        self.start()  # start the thread
        self.val = 0

    def run(self):
        while True:
            if self.stop_work_thread == 1:
                break
            time.sleep(1)
            self.val += 1
            wx.CallAfter(pub.sendMessage, "update", step=self.val)
        wx.CallAfter(pub.sendMessage, "finish")
        return

    def stop(self):
        self.stop_work_thread = 1

class Progress(wx.Frame):
    def __init__(self, parent, title):
        super(Progress, self).__init__(parent, title = title,size = (500,300))
        self.panel = wx.Panel(self)
        self.start_btn = wx.Button(self.panel, label="Start", pos=(20,50))
        self.start_btn.Bind(wx.EVT_BUTTON, self.onStart)
        self.stop_btn =wx.ToggleButton(self.panel, label="Stop", pos=(20, 90))
        self.stop_btn.Bind(wx.EVT_TOGGLEBUTTON, self.onCancel)
        self.logger = wx.TextCtrl(self.panel, pos=(150,0), size=(200,200), style=wx.TE_MULTILINE | wx.TE_READONLY)
        self.stop_btn.Disable()
        self.Bind(wx.EVT_CLOSE, self.onExit)

    def onUpdate(self, step):
        step = str(step)+'\n'
        self.logger.AppendText(step)

    def onStart(self, event):
        self.logger.Clear()
        pub.subscribe(self.onUpdate, "update")
        pub.subscribe(self.onFinish, "finish")
        btn = event.GetEventObject()
        self.start_btn.Disable()
        self.work = WorkThread()
        Progress(self.panel,'Incrementer')
        self.stop_btn.Enable()

    def onCancel(self, event):
        """Cancel thread process"""
        try:
            self.work.stop()
            self.work.join()
        except:
            pass

    def onFinish(self):
        """thread process finished"""
        try:
            pub.unsubscribe(self.onUpdate, "update")
            pub.unsubscribe(self.onFinish, "finish")
        except:
            pass
        self.start_btn.Enable()
        self.stop_btn.Disable()

    def onExit(self, event):
        self.onCancel(None)
        self.onFinish()
        self.Destroy()

app = wx.App()
frame = Progress(None,'Incrementer')
frame.Show(True)
app.MainLoop()