如何解决将Python记录器输出重定向到wxPython文本控件
我正在尝试将Python记录器的输出从外部脚本重定向到wxPython文本控件。 GUI脚本在单独的线程中执行外部脚本。我试图遵循此link中接受的答案所描述的方法,但无法使其按预期发挥作用。
以下是我到目前为止尝试过的内容:
# -*- coding: UTF-8 -*-
#--------------------------------------------------------------------------------------------------
import logging
from threading import Thread
import wx
import wx.lib.newevent as NE
#---------------------------------------------------------------------------------------------------
from module_sine import sin_fun
####################################################################################################
# Create event for the logger
wxLogEvent,EVT_WX_LOG_EVENT = NE.NewEvent()
#####################################################################################################
# Notification event for thread completion
UpdateEvent,EVT_UPDATE = NE.NewEvent()
#####################################################################################################
class wxLogHandler(logging.Handler):
"""
A handler class which sends log strings to a wx object
"""
def __init__(self,wxDest=None):
"""
Initialize the handler
@param wxDest: the destination object to post the event to
@type wxDest: wx.Window
"""
logging.Handler.__init__(self)
self.wxDest = wxDest
self.level = logging.DEBUG
def flush(self):
"""
does nothing for this handler
"""
pass
def emit(self,record):
"""
Emit a record.
"""
try:
msg = self.format(record)
event = wxLogEvent(message=msg,levelname=record.levelname)
wx.PostEvent(self.wxDest,event)
except (KeyboardInterrupt,SystemExit):
raise
except:
self.handleError(record)
#####################################################################################################
class MyFrame(wx.Frame):
def __init__(self,*args,**kwds):
kwds["style"] = kwds.get("style",0) | wx.DEFAULT_FRAME_STYLE | wx.STAY_ON_TOP
wx.Frame.__init__(self,**kwds)
self.SetSize((400,300))
self.SetTitle("TEST")
self.panel_1 = wx.Panel(self,wx.ID_ANY)
sizer_1 = wx.BoxSizer(wx.VERTICAL)
self.label_3 = wx.StaticText(self.panel_1,wx.ID_ANY,label="",style=wx.ALIGN_CENTER_HORIZONTAL)
sizer_1.Add(self.label_3,wx.ALL,5)
grid_sizer_2 = wx.FlexGridSizer(2,1,1)
sizer_1.Add(grid_sizer_2,wx.EXPAND,0)
self.text_ctrl_3 = wx.TextCtrl(self.panel_1,"",style=wx.HSCROLL | wx.TE_MULTILINE | wx.TE_READONLY | wx.TE_RICH2)
grid_sizer_2.Add(self.text_ctrl_3,0)
grid_sizer_2.Add((0,0),0)
grid_sizer_1 = wx.FlexGridSizer(5,2,1)
sizer_1.Add(grid_sizer_1,0)
label_1 = wx.StaticText(self.panel_1,"x")
grid_sizer_1.Add(label_1,5)
self.text_ctrl_1 = wx.TextCtrl(self.panel_1,"")
grid_sizer_1.Add(self.text_ctrl_1,0)
label_2 = wx.StaticText(self.panel_1,"y")
grid_sizer_1.Add(label_2,5)
self.text_ctrl_2 = wx.TextCtrl(self.panel_1,"")
grid_sizer_1.Add(self.text_ctrl_2,0)
grid_sizer_1.Add((0,0)
self.button_1 = wx.Button(self.panel_1,"Save")
self.button_1.SetFocus()
grid_sizer_1.Add(self.button_1,0)
self.button_2 = wx.Button(self.panel_1,"Start")
grid_sizer_1.Add(self.button_2,0)
self.button_3 = wx.Button(self.panel_1,"Stop")
grid_sizer_1.Add(self.button_3,0)
grid_sizer_2.AddGrowableRow(0)
grid_sizer_2.AddGrowableCol(0)
self.panel_1.SetSizer(sizer_1)
self.Layout()
self.Bind(wx.EVT_BUTTON,self.OnClick_Save,self.button_1)
self.Bind(wx.EVT_BUTTON,self.OnClick_Start,self.button_2)
self.Bind(wx.EVT_BUTTON,self.OnClick_Stop,self.button_3)
self.Bind(wx.EVT_CLOSE,self.CloseWindow)
# Set up event handler for any worker thread updates
self.Bind(EVT_UPDATE,self.OnUpdate)
# Indicate there is not any worker thread yet
self.worker = None
# Set up event handler for the logger
self.Bind(EVT_WX_LOG_EVENT,self.onLogEvent)
#------------------------------------------------------------------------------------------------
# Logger
logging.basicConfig(level=logging.DEBUG,format='%(message)s')
logger = logging.getLogger('testing')
logger.setLevel(logging.DEBUG)
# Text handler
txthandler = wxLogHandler(self.text_ctrl_3)
logger.addHandler(txthandler)
txthandler.setLevel(logging.DEBUG)
FORMAT = "%(message)s"
txthandler.setFormatter(logging.Formatter(FORMAT))
#------------------------------------------------------------------------------------------------
self.button_2.disable()
self.button_3.disable()
#------------------------------------------------------------------------------------------------
self.my_data = []
#----------------------------------------------------------------------------------------------------
def OnClick_Save(self,event):
x = float(self.text_ctrl_1.GetValue())
self.my_data.append(x)
y = float(self.text_ctrl_2.GetValue())
self.my_data.append(y)
self.button_2.Enable()
self.button_3.Enable()
event.Skip()
#----------------------------------------------------------------------------------------------------
def OnClick_Start(self,event):
"""
Run calc. in the thread
"""
inp_val = self.my_data # entered values that will be passed to the thread
if not self.worker:
self.label_3.SetLabel('Run started')
self.worker = WorkerThread(self,inp_val)
self.button_2 = event.GetEventObject()
self.button_2.disable()
self.label_3.SetLabel('Running ...')
event.Skip()
#------------------------------------------------------------------------------------
def OnClick_Stop(self,event):
"""
Abort calculation
"""
if self.worker:
self.label_3.SetLabel('Trying to abort run ...')
self.worker.abort()
event.Skip()
#-----------------------------------------------------------------------------------
def OnUpdate(self,event):
"""Show updates"""
if event.data is None:
# Thread aborted
self.label_3.SetLabel('Run aborted')
self.button_2.Enable()
self.text_ctrl_3.SetValue("") # Clear any text transmitted to the text control when the thread is aborted.
self.my_data.clear() # remove values from the list
else:
# Thread completed
self.label_3.SetLabel('%s' % event.data)
self.button_2.Enable()
self.my_data.clear() # remove values from the list
# In either event,the worker is done
self.worker = None
#------------------------------------------------------------------------------------------------
def onLogEvent(self,event):
'''
Add event.message to text window
'''
msg = event.message.strip("\r")+"\n"
self.text_ctrl_3.WriteText(msg)
event.Skip()
#------------------------------------------------------------------------------------------------
def CloseWindow(self,event): # Not sure if this is a good implementation for the close window method.
WorkerThread.abort(self)
self.Destroy()
####################################################################################################
class WorkerThread(Thread):
"""Worker Thread Class."""
#-----------------------------------------------------------------------------------------------
def __init__(self,notify_win,inp_val):
"""Init Worker Thread Class."""
Thread.__init__(self)
self._notify_win = notify_win
self.inp_val = inp_val
self.daemon = True
self._want_abort = False
self.start()
#-----------------------------------------------------------------------------------------------
def run(self):
"""Run Worker Thread."""
# This is the function executing in the new thread.
[x,y] = self.inp_val
sin_fun(x,y)
if self._want_abort:
wx.PostEvent(self._notify_win,UpdateEvent(data=None))
return
wx.PostEvent(self._notify_win,UpdateEvent(data='Run completed successfully!'))
#-----------------------------------------------------------------------------------------------
def abort(self):
"""Abort Worker Thread."""
self._want_abort = True
####################################################################################################
class MyApp(wx.App):
def OnInit(self):
self.frame = MyFrame(None,"")
self.SetTopWindow(self.frame)
self.frame.Show()
return True
if __name__ == "__main__":
Test = MyApp(False)
Test.MainLoop()
这是我正在尝试的外部脚本:
# -*- coding: UTF-8 -*-
import logging
import math
def sin_fun(x,y):
logger = logging.getLogger('testing')
for i in range(0,2):
a = (math.sin(x) + math.cos(y))*(x/y + i)
logger.debug(a)
我正在使用Windows 10,Python 3.8.5和wxPython 4.1.0。 非常感谢您的帮助。 预先非常感谢。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。