* My apologies if this is a repost. I tried emailing the list from a
different account, and I didn't see this go through.
I’ve been getting unexpected segmentation faults when using the
RemoveItem/Remove methods in wxPython (2.8.10 and 2.9.0) in conjuction
with AppendItem. I’m going to attempt to attach a python script that
seg faults under both Windows and Linux GTK, but in case the
attachments don’t come through, the code is copied and pasted below.
The first script is the wxPython version that seg faults. Simply
click the button and the handler will attempt to remove the item from
the file menu and then will re-add it. Once the item has been removed
and re-added, the menu becomes corrupted and a second click or simply
expanding the menu will result in a seg fault. Now the one weird
thing I noticed is that if I explicity pass in the original reference
of the menu item I added instead of getting a new reference from
wxMenu.GetMenuItems(), the seg fault is avoided. To illustrate this
behavior, uncomment the block of code in the button handler that is
prefaced with the comment “This Works”. The second source file is a
pure wxWidgets implementation that sets up a similar scenario and
works. To execute the handler that removes and re-adds the menu
items, click the item under the edit menu, and the handler will remove
and re-add the items in the file menu.
Per the wxWidgets documentation, wxMenu.Remove() shouldn’t delete the
underlying menu item, so I should be able to re-add it.
Josh
##############Begin
test.py####################################################
import wx
import sys
class MyFrame(wx.Frame):
def __init__(self, parent, *args, **kwargs):
wx.Frame.__init__(self, parent, *args, **kwargs)
panel = wx.Panel(self)
panel.SetBackgroundColour('pink')
button = wx.Button(panel, wx.ID_ANY, "HI", pos=(100, 100))
panel.Bind(wx.EVT_BUTTON, self.OnClick)
sizer = wx.BoxSizer(wx.VERTICAL)
sizer.Add(panel, 1, wx.EXPAND)
self.SetSizer(sizer)
self.menu = wx.Menu()
self.menuBar = wx.MenuBar()
self.menuBar.Append(self.menu, "Test")
self.item = wx.MenuItem(self.menu, wx.ID_ANY, "I will be
removed/added on button click")
self.menu.AppendItem(self.item)
self.SetMenuBar(self.menuBar)
def OnClick(self, event):
print >>sys.stderr, "OnClick()", self.item
for item in self.menu.GetMenuItems():
print >>sys.stderr, "Removing Item", item, "...",
self.item
self.menu.RemoveItem(item)
#This doesn't work either
# for item in self.menu.GetMenuItems():
# print >>sys.stderr, "Removing Item", item.GetId(), "...",
self.item.GetId()
# self.menu.Remove(item.GetId())
#This Works
# print >>sys.stderr, "Removing Item", self.item, "..."
# self.menu.RemoveItem(self.item)
print >>sys.stderr, "Readding Item...", self.item
self.menu.AppendItem(self.item)
if __name__ == "__main__":
app = wx.App(0)
frame = MyFrame(None, title="HELLO")
frame.SetSize((600, 400))
frame.Show()
app.MainLoop()
#################################End
test.py############################################
////////////////////////////////////////Begin
wx.cpp//////////////////////////////////////////////////////////
#include "wx/wx.h"
#include <iostream>
using std::cout;
using std::endl;
class MyApp: public wxApp
{
virtual bool OnInit();
};
class MyFrame: public wxFrame
{
public:
MyFrame(const wxString& title, const wxPoint& pos, const wxSize&
size);
void OnQuit(wxCommandEvent& event);
void OnAbout(wxCommandEvent& event);
void OnHi(wxCommandEvent& event);
DECLARE_EVENT_TABLE()
protected:
wxMenu* menuFile;
wxMenuItem* aboutItem;
wxMenuItem* exitItem;
};
enum
{
ID_Quit = 1,
ID_About,
};
BEGIN_EVENT_TABLE(MyFrame, wxFrame)
EVT_MENU(ID_Quit, MyFrame::OnQuit)
EVT_MENU(ID_About, MyFrame::OnAbout)
END_EVENT_TABLE()
IMPLEMENT_APP(MyApp)
bool MyApp::OnInit()
{
MyFrame *frame = new MyFrame( _T("Hello World"), wxPoint(50,50),
wxSize(450,340) );
frame->Show(TRUE);
SetTopWindow(frame);
return TRUE;
}
MyFrame::MyFrame(const wxString& title, const wxPoint& pos, const
wxSize& size)
: wxFrame((wxFrame *)NULL, -1, title, pos, size)
{
menuFile = new wxMenu;
wxMenu *menuEdit = new wxMenu;
aboutItem = menuFile->Append( ID_About, _T("&About...") );
exitItem = menuFile->Append( ID_Quit, _T("E&xit") );
wxMenuItem* item = menuEdit->Append(wxID_ANY, _T("HI"));
Bind(wxEVT_COMMAND_MENU_SELECTED, &MyFrame::OnHi, this, item->GetId
());
wxMenuBar *menuBar = new wxMenuBar;
menuBar->Append( menuFile, _T("&File") );
menuBar->Append(menuEdit, _T("Edit"));
SetMenuBar( menuBar );
CreateStatusBar();
SetStatusText( _T("Welcome to wxWindows!") );
}
void MyFrame::OnQuit(wxCommandEvent& WXUNUSED(event))
{
Close(TRUE);
}
void MyFrame::OnAbout(wxCommandEvent& WXUNUSED(event))
{
wxMessageBox(_T("This is a wxWindows Hello world sample"),
_T("About Hello World"), wxOK | wxICON_INFORMATION, this);
}
void MyFrame::OnHi(wxCommandEvent& WXUNUSED(event))
{
cout << "OnHi" << endl;
wxMenuItemList list = menuFile->GetMenuItems();
wxMenuItemList::iterator iter = list.begin();
for(;iter != list.end(); iter++) {
cout << "Removing: " << (*iter)->GetId() << endl;
menuFile->Remove(*iter);
}
cout << "Readding" << endl;
menuFile->Append(aboutItem);
menuFile->Append(exitItem);
}
///////////////////////////////////////////////////End
wx.cpp////////////////////////////////////////////