当尝试在单独的线程中运行wxPython的GUI构造和事件循环时,我遇到一个问题,当应用程序关闭时,会出现调试警报消息,请参阅图像:
有没有办法将弹出的消息重定向到控制台?或者只是禁用那些警报警告消息?
我发现有一个函数DisableAsserts(),但我不知道如何从python脚本调用这个函数,这个函数是从C ++导出的吗?
还有另一种函数app.SetAssertMode(),但我测试了它,发现它对禁用或重定向警报消息没有任何影响。
我希望你的建议能解决这个问题,谢谢。
BTW,详细描述了为什么我需要在一个单独的线程中运行wxPython可以找到alert message pops up when I close a console application if I run wxPython app.MainLoop() in a seperate thread - Google Groups
编辑:
我发现在GDB的python接口下使用单独的wxPython Gui线程是一个质量。我可以使用旧版本的wxPython2.8.12来避免调试警报消息。对于GDB,我需要在def invoke(self, arg, from_tty):
中定义一个自定义命令,如果我键入自定义命令,将调用该命令。一旦我输入命令,就会运行一个新线程,并构造一些wxPython GUI,并将线程转到Mainloop。如果我关闭Gui Window,Thread的run函数刚刚完成,但由于某些未知原因,有时候,线程对象不会立即被破坏。如果我再次运行自定义命令,有时,GDB只是崩溃,或者显示一个新窗口,但我看到打印命令的内容将转到它自己的窗口,而不是GDB的stdout或stderr,请参见下面的屏幕截图。
我相信在一个单独的线程中使用wxPython GUI在这里仍然不太稳定。如果你想尝试,这是我的测试代码。
import gdb
import sys
import threading
from threading import Thread
import ctypes
# Used to guarantee to use at least Wx2.8
import wxversion
wxversion.ensureMinimal('2.8')
import matplotlib
matplotlib.use('WXAgg')
from matplotlib import pyplot as plt
# uncomment the following to use wx rather than wxagg
#matplotlib.use('WX')
#from matplotlib.backends.backend_wx import FigureCanvasWx as FigureCanvas
# comment out the following to use wx rather than wxagg
matplotlib.use('WXAgg')
from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg as FigureCanvas
from matplotlib.backends.backend_wx import NavigationToolbar2Wx
from matplotlib.figure import Figure
from numpy import arange, sin, pi
import wx
class CanvasFrame(wx.Frame):
def __init__(self):
wx.Frame.__init__(self,None,-1,
'CanvasFrame',size=(550,350))
self.SetBackgroundColour(wx.NamedColour("WHITE"))
self.figure = Figure()
self.axes = self.figure.add_subplot(111)
t = arange(0.0,3.0,0.01)
s = sin(2*pi*t)
self.axes.plot(t,s)
self.canvas = FigureCanvas(self, -1, self.figure)
self.sizer = wx.BoxSizer(wx.VERTICAL)
self.sizer.Add(self.canvas, 1, wx.LEFT | wx.TOP | wx.GROW)
self.SetSizer(self.sizer)
self.Fit()
self.add_toolbar() # comment this out for no toolbar
def add_toolbar(self):
self.toolbar = NavigationToolbar2Wx(self.canvas)
self.toolbar.Realize()
if wx.Platform == '__WXMAC__':
# Mac platform (OSX 10.3, MacPython) does not seem to cope with
# having a toolbar in a sizer. This work-around gets the buttons
# back, but at the expense of having the toolbar at the top
self.SetToolBar(self.toolbar)
else:
# On Windows platform, default window size is incorrect, so set
# toolbar width to figure width.
tw, th = self.toolbar.GetSizeTuple()
fw, fh = self.canvas.GetSizeTuple()
# By adding toolbar in sizer, we are able to put it at the bottom
# of the frame - so appearance is closer to GTK version.
# As noted above, doesn't work for Mac.
self.toolbar.SetSize(wx.Size(fw, th))
self.sizer.Add(self.toolbar, 0, wx.LEFT | wx.EXPAND)
# update the axes menu on the toolbar
self.toolbar.update()
def OnPaint(self, event):
self.canvas.draw()
class MyApp(wx.App):
def OnInit(self):
'Create the main window and insert the custom frame'
frame = CanvasFrame()
whnd = frame.GetHandle()
# SW_SHOW = 5, so we force to set on the WS_VISIBLE window style, see below as a reference
# Window Styles (Windows) - http://msdn.microsoft.com/en-us/library/windows/desktop/ms632600(v=vs.85).aspx
# ShowWindow function (Windows) - http://msdn.microsoft.com/en-us/library/windows/desktop/ms633548(v=vs.85).aspx
ctypes.windll.user32.ShowWindow(whnd, 5)
frame.Show(True)
return True
class MyThread (threading.Thread):
def __init__(self, thread_id = None, name = None, image = None):
threading.Thread.__init__(self)
self.thread_id = thread_id
self.name = name
self.image = image
self.app = None
self.start()
def __del__(self):
print "MyThrad dead"
#ctypes.windll.user32.MessageBoxA(None, 'MyThread dead', 'Window title', 0)
def run(self):
self.app = MyApp(False)
self.app.MainLoop()
#ctypes.windll.user32.MessageBoxA(None, 'Main loop finish', 'Window title', 0)
print "MyThread run() finish"
def set_image(self, image):
self.image = image
print "image set/updated"
class PlotterCommand(gdb.Command):
def __init__(self):
super(PlotterCommand, self).__init__("plot",
gdb.COMMAND_DATA,
gdb.COMPLETE_SYMBOL)
print "Constructor of Plotter object"
self.thread1 = None
sys.stdout.flush()
def __del__( self ):
print 'Destructor of Plotter object'
sys.stdout.flush()
def invoke(self, arg, from_tty):
#args = gdb.string_to_argv(arg)
# generally, we type "plot someVar" in the GDB commandline
#v = gdb.parse_and_eval(args[0])
# do something with the v object
thread1 = MyThread(1, "Thread 1", None)
print "Finish invoke plot command"
sys.stdout.flush()
PlotterCommand()
将上面的代码保存为“my.py”,在GDB下调试时,可以输入命令source my.py
来加载那些python代码,现在你有一个名为plot
的新命令,你可以在GDB中键入plot
,将显示一个wxPython窗口。您可以关闭窗口,再次键入plot
,然后会出现问题。或者,您可以离开窗口,只需键入plot
,您就会收到更多错误。
EDIT2
“stdout / stderr”窗口问题已修复,我可以通过self.app = MyApp(False)
来禁用此日志窗口。