I'm hoping for some advice. I am getting the above error in my wx.grid after
deleting a row and attempting to re-add a new one.
I've attached some example code that shows the problem.
In short, if I launch the program and click the "Add" button below the grid, a
new row is displayed with a GridCellEditor in column 0 for each new row added.
If I set up a bind method to allow the user to right click on the row number, it
allows them to delete that row. That works properly.
However, when I then click Add to add a new row, the GridCellEditor call fails.
I'm assuming I should have to somehow refresh the reference to the celleditor
but can't figure out how to do that.
Does anyone have any ideas?
Thanks!
import wx
import wx.grid
class MyWizard(wx.Frame):
def __init__(self, parent, id):
wx.Frame.__init__(self, parent, id, 'MyWizard v1' , size=(750,550),
style=wx.DEFAULT_FRAME_STYLE ^ (wx.MINIMIZE_BOX |
wx.MAXIMIZE_BOX))
self.SetIcon(wx.Icon('icons\\Sidewinder.ico', wx.BITMAP_TYPE_ICO))
self.CenterOnScreen()
#Base Panel with common widgets such as navigation widgets, buttons, etc
self.basepanel = BasePanel(self)
self.basepanel.Fit()
self.basepanel.Show()
self.basepanel.Layout()
class BasePanel(wx.Panel):
def __init__(self, parent):
wx.Panel.__init__(self, parent, wx.ID_ANY)
self.parent = parent
self.__do_layout()
def __do_layout(self):
#top level vertical sizer
vsizer = wx.BoxSizer(wx.VERTICAL)
#horizontral sizer for button menu at bottom of frame
hsizer = wx.BoxSizer(wx.HORIZONTAL)
#horizontal box for bitmap image
bitmapbox = wx.BoxSizer(wx.HORIZONTAL)
sb = wx.StaticBitmap(self, wx.ID_ANY,
wx.BitmapFromImage(wx.Image("SomeIcon.ico", wx.BITMAP_TYPE_ANY)))
bitmapbox.Add(sb, 0, wx.ALL, 5)
#vertical box for holding main part of panel (rt of the image)
vmainbox = wx.BoxSizer(wx.VERTICAL)
mainbox = wx.BoxSizer(wx.HORIZONTAL)
self.currentpanel = BurbPanel(self)
mainbox.Add(self.currentpanel)
#add horizontal elements
vmainbox.Add(mainbox, 0, wx.TOP, 5)
bitmapbox.Add(vmainbox, 0, wx.ALL, 5)
vsizer.Add(bitmapbox, 0, wx.ALL | wx.LEFT, 5)
vsizer.Add(wx.StaticLine(self, wx.ID_ANY), 0, wx.ALL | wx.EXPAND, 5)
self.SetSizerAndFit(vsizer)
self.mainbox = mainbox
class BurbPanel(wx.Panel):
def __init__(self, parent):
wx.Panel.__init__(self, parent, wx.ID_ANY)
self.parent = parent
self.__do_layout()
def __do_layout(self):
#Main overall vertical sizer
vmainbox = wx.BoxSizer(wx.VERTICAL)
mainbox = wx.BoxSizer(wx.HORIZONTAL)
title = wx.StaticText(self, wx.ID_ANY, "My Grid", (0,0))
title.SetFont(wx.Font(11, wx.SWISS, wx.NORMAL, wx.BOLD))
mainbox.Add(title, 0, wx.EXPAND, 1)
descbox = wx.BoxSizer(wx.HORIZONTAL)
descpg = wx.StaticText(self, wx.ID_ANY, "This is a grid example", (0,0))
descpg.SetFont(wx.Font(8, wx.SWISS, wx.NORMAL, wx.NORMAL))
descbox.Add(descpg, 0, wx.EXPAND, 1)
burbmapbox = wx.BoxSizer(wx.HORIZONTAL)
self.burbgrid = BurbGrid(self)
#Put a tooltip on the cells in a column
self.burbgrid.GetGridWindow().Bind(wx.EVT_MOTION, self.burbgrid.onMouseOver)
burbmapbox.Add(self.burbgrid, 1, wx.ALL | wx.EXPAND, 5)
addbuttonbox = wx.BoxSizer(wx.HORIZONTAL)
addintbutton = wx.Button(self, wx.ID_ANY, label='Add')
addintbutton.SetToolTip(wx.ToolTip("Test Tool Tip"))
addbuttonbox.Add(addintbutton, 0, wx.ALL | wx.EXPAND, 0)
vmainbox.Add(mainbox, 0, wx.ALL | wx.BOTTOM, 5)
vmainbox.Add(descbox, 0, wx.ALL | wx.BOTTOM, 5)
vmainbox.Add(burbmapbox, 0, wx.ALL | wx.BOTTOM, 0)
vmainbox.Add(addbuttonbox, 0, wx.EXPAND | wx.BOTTOM, 0)
self.Bind(wx.EVT_BUTTON, self.burbgrid.OnAddClick, addintbutton)
self.addbuttonbox = addbuttonbox
self.vmainbox = vmainbox
self.SetSizerAndFit(vmainbox)
class BurbGrid(wx.grid.Grid):
def __init__(self, parent):
wx.grid.Grid.__init__(self, parent)
#Column Labels
self.typeColumn = "Type"
self.ipAddressColumn = "IP Address"
self.maskColumn = "Subnet Mask"
self.interfaceColumn = "Interface"
self.burbNameColumn = "Zone Name"
self.rowToDelete = None
self.columns = {
0 : self.typeColumn, \
1 : self.ipAddressColumn, \
2 : self.maskColumn, \
3 : self.interfaceColumn, \
4 : self.burbNameColumn }
self.SetRowLabelSize(17)
self.SetColLabelSize(15)
self.SetSizeHints(417,295)
#Set the drop down choice editor
self.tChoiceEditor = wx.grid.GridCellChoiceEditor(['INTERFACE',
'ROUTE'], allowOthers=True)
self.Bind(wx.grid.EVT_GRID_CELL_CHANGE, self.validateCell)
self.Bind(wx.grid.EVT_GRID_LABEL_RIGHT_CLICK, self.OnLabelRightClick)
self.interfaceDataHash = {}
self.setupTable(self.interfaceDataHash)
def setupTable(self, interfaceDataHash):
self.CreateGrid(len(interfaceDataHash), len(self.columns)) #x and y for
the grid
attr = wx.grid.GridCellAttr()
attr.SetEditor(self.tChoiceEditor)
#print margin heading
for x in range(len(self.columns)):
self.SetColLabelValue(x, self.columns[x])
if interfaceDataHash is None:
return
for col in range (len(interfaceDataHash)):
print "Row: %s" % col
self.SetAttr(col, 0, attr)
entry = interfaceDataHash[col]
for index, item in enumerate(entry):
self.SetCellValue(col, index, entry[index])
if entry[index] == "":
self.SetCellBackgroundColour(col, index, "light blue")
def parseGrid(self):
pass
def validateCell(self, evt):
pass
############################h#################
# Add a new cell row if the user selects the "Add" button
#############################################
def OnAddClick(self, evt):
self.AppendRows(1, False)
attr = wx.grid.GridCellAttr()
attr.SetEditor(self.tChoiceEditor)
self.SetAttr(self.GetNumberRows()-1, 0, attr)
#Set these cells initially blue
for col in range (len(self.columns)):
self.SetCellBackgroundColour(self.GetNumberRows()-1, col, "light
blue")
self.twiddle()
# Delete a cell row on right click
def OnLabelRightClick(self, evt):
row = int(self.GetRowLabelValue(evt.GetRow()))
if not hasattr(self, "operation"):
self.operation = wx.NewId()
menu = wx.Menu()
deleteText = "Delete row %s?" % row
self.rowToDelete = row-1
item = wx.MenuItem(menu, self.operation, deleteText)
menu.AppendItem(item)
self.Bind(wx.EVT_MENU, self.OnDeleteRow, id=self.operation)
self.PopupMenu(menu)
menu.Destroy()
def OnDeleteRow(self, evt):
print "Deleting row 1"
self.DeleteRows(self.rowToDelete, 1, True)
#Tool tip when mouse over cell taken from:
#http://www.blog.pythonlibrary.org/2010/04/04/wxpython-grid-tips-and-tricks/
def onMouseOver(self, evt):
#Displays a tooltip over any cell in a certain column
x, y = self.CalcUnscrolledPosition(evt.GetX(), evt.GetY())
coords = self.XYToCell(x, y)
column = coords[1]
row = coords[0]
if column == 0:
evt.GetEventObject().SetToolTipString("Values: INTERFACE|ROUTE")
elif column == 1:
evt.GetEventObject().SetToolTipString("Enter a valid IP Address")
elif column == 2:
evt.GetEventObject().SetToolTipString("Enter a valid subnet mask")
elif column == 3:
evt.GetEventObject().SetToolTipString("Interface name of existing
firewall you are migrating policy from. i.e. bc0")
elif column == 4:
evt.GetEventObject().SetToolTipString("Name of McAfee Firewall zone
to map this traffic to")
############################h#################
# This helps resize the slide bars when the grid is refreshed because a new
cell was added
#############################################
def twiddle(self):
x,y = self.GetSize()
self.SetSize((x, y+1))
self.SetSize((x,y))
if __name__ =='__main__':
app = wx.PySimpleApp()
frame = MyWizard(parent=None, id=-1)
frame.Show()
app.MainLoop()
Since you are reusing the same editor object you need to call its
IncRef() method each time you use it with a new cell attr object.
P.S. Next time please attach your sample code to an email instead of
pasting it in to the body of the message, so lines are not improperly
wrapped or indentation messed up.
--
Robin Dunn
Software Craftsman
http://wxPython.org
WIll do on the code submissions in the future - thanks!
--
To unsubscribe, send email to wxPython-user...@googlegroups.com
or visit http://groups.google.com/group/wxPython-users?hl=en