线程记录到 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()
我正在尝试将线程中的值打印到在不同 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()