python - wxPython无法退出

标签 python matplotlib wxpython

我的 wxPython GUI 要么因段错误而退出,要么使用标准选项根本无法退出。唯一成功的退出选项(没有错误)是 wx.Exit,我知道这不是一个很好的做法。我已将问题归结为几个因素,但我对它们为何产生这种影响感到摸不着头脑。

使用wxPython检查器(wx.lib.inspection.InspectionTool()),我已经能够确定当我运行某些pylab函数时正在创建一个FigureFrameWxAgg(pylab.xticks()是创建它的函数)在这里,但我还没有追踪到具有此效果的每个函数)。我不知道这个窗口是做什么用的。它是看不见的并且似乎没有做任何事情。然而,这个窗口完全搞乱了我的 GUI 的关闭。如果我使用 self.Destroy,Python 不会完全关闭。如果我使用 sys.exit,则会出现段错误。我需要捕获 wx.EVT_CLOSE 以便我可以提示用户保存他/她的工作。

以下是简化版 GUI 的代码:

import matplotlib
matplotlib.use('WXAgg')
from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg as FigCanvas
import wx
import wx.grid
import wx.lib.scrolledpanel
import wx.lib.inspection
import sys
import pylab

class my_frame(wx.Frame):

    def __init__(self):
        wx.Frame.__init__(self, None, -1, 'Many Rows')
        self.InitUI()

    def InitUI(self):
        self.panel = wx.Window(self, size=(200, 200))
        hbox_all= wx.BoxSizer(wx.HORIZONTAL)
        self.create_menubar()

        self.fig1 = pylab.Figure((5, 5), dpi=100)
        self.canvas1 = FigCanvas(self.panel, -1, self.fig1)
        self.fig1.text(0.01,0.98,"Arai plot",{'family':'Arial', 'fontsize':10, 'style':'normal','va':'center', 'ha':'left' })
        self.araiplot = self.fig1.add_axes([0.1,0.1,0.8,0.8])
        self.araiplot.clear()
        self.araiplot.plot(range(5),range(5),lw=0.75,clip_on=False)
        xt = pylab.xticks()

        grid = wx.grid.Grid(self.panel)
        grid.ClearGrid()
        grid.CreateGrid(100, 100)
        grid.AutoSize()

        hbox_all.AddSpacer(self.canvas1)
        hbox_all.AddSpacer(20)
        hbox_all.AddSpacer(grid)
        hbox_all.AddSpacer(20)

        self.panel.SetSizer(hbox_all)
        hbox_all.Fit(self)
        self.Centre()
        self.Show()

    def create_menubar(self):
        """                                                                                                                           
        Create menu bar                                                                                                               
        """
        self.menubar = wx.MenuBar()
        menu_file = wx.Menu()
        menu_file.AppendSeparator()
        m_exit = menu_file.Append(wx.ID_EXIT, "Quit", "Quit application")
        self.Bind(wx.EVT_CLOSE, self.on_menu_exit)
        self.menubar.Append(menu_file, "&File")
        self.SetMenuBar(self.menubar)


    def on_menu_exit(self, event):
        self.Destroy() # this doesn't quit Python fully, unless I comment out 'matplotlib.use('WXAgg')' 
        #for w in wx.GetTopLevelWindows():
        #    if w.Title == 'Figure 1':
        #        w.Destroy()  # if I pre-destroy the FigureFrameWxAgg window, I get a PyDeadObjectError when I run self.Destroy
        # self.Destroy() #                              
        # wx.Exit() # forces the program to exit, with no clean up.  works, but not an ideal solution                             
        #sys.exit() # program closes, but with segmentation error                                                                 
        #self.Close()  # creates infinite recursion error, because we have a binding to wx.EVT_CLOSE  


if __name__ == '__main__':
    app = wx.PySimpleApp(redirect=False)                                     
    app.frame = my_frame()
    if '-i' in sys.argv:
        wx.lib.inspection.InspectionTool().Show()
    app.MainLoop()

为了增加一层复杂性,sys.exit() 的段错误仅发生在我安装了 Brew 的 Python 上。 Sys.exit() 与 Canopy Python 配合良好。

我的问题是:如何修复此错误?而且,使用 wx.Exit() 真的那么糟糕吗?

最佳答案

您的示例存在几个问题:

  1. 不要在 GUI 应用程序中使用 pylab,因为它带有自己的主循环(当 wxPython 主循环退出时,它不会退出)。你必须杀死 pylab。

    # both not required
    # matplotlib.use('WXAgg')
    # import pylab
    # use instead
    from matplotlib.figure import Figure
    ...
    def __init__(# ...
        ...
        self.fig1 = Figure((5, 5), dpi=100)
    
  2. 您的菜单项“关闭”不起作用(至少在 Windows 上不起作用)。 wx.ID_EXIT 用于对话框中的按钮。不要问我哪些预定义 ID 是用于菜单的。

        ID_QUIT = wx.NewId()
        menu_file.Append(ID_QUIT , "Quit", "Quit application")
        # 
        self.Bind(wx.EVT_MENU, self.on_quit, id=ID_QUIT)
    
    def on_quit(self, evt):
        self.Close()
    
  3. 在这种情况下,没有必要绑定(bind)到wx.EVT_CLOSE。如果你想在关闭事件上做一些事情,你必须跳过它。当你跳过它时,wxPython会自己处理它。

        self.Bind(wx.EVT_CLOSE, self.on_close)
        ...
    
    def on_close(self, evt):
        # you can veto the close here or perform cleanup
        evt.Skip() 
    

如果您相应地更改代码,wxPython 将正确关闭所有内容。

关于python - wxPython无法退出,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28103710/

相关文章:

python - CSV 模块属性错误

python 在 x 轴上旋转值以不重叠

python - PairGrid 与 Seaborn 中的 Hexbin 图

python - 当考虑速度时行的 numpy 平均值

python - 如何在 Python 中编写带有图案和颜色的条形图?

python - wxpython 中的 wx.ICON_ 选项列表

python - wx.TreeCtrl 拖放、复制和移动

python - 如何线程化一个 wxpython 进度条 GUI?

python - 为什么自动完成有时在 python IDE 中不起作用

python - 在 Mayavi 中设置 Nan 颜色