Python создать событие для флажка ObjectListView
Как я могу создать событие, когда флажок установлен / снят? Для этого примера я просто хочу, чтобы он напечатал данные об объекте, который был проверен
Примечание: этот код был изменен с http://www.blog.pythonlibrary.org/2009/12/23/wxpython-using-objectlistview-instead-of-a-listctrl/ как учебное упражнение
import wx
from ObjectListView import ObjectListView, ColumnDefn
########################################################################
class Book(object):
"""
Model of the Book object
Contains the following attributes:
'ISBN', 'Author', 'Manufacturer', 'Title'
"""
#----------------------------------------------------------------------
def __init__(self, title, author, isbn, mfg):
self.isbn = isbn
self.author = author
self.mfg = mfg
self.title = title
########################################################################
class MainPanel(wx.Panel):
#----------------------------------------------------------------------
def __init__(self, parent):
wx.Panel.__init__(self, parent=parent, id=wx.ID_ANY)
self.products = [Book("wxPython in Action", "Robin Dunn",
"1932394621", "Manning"),
Book("Hello World", "Warren and Carter Sande",
"1933988495", "Manning")
]
self.dataOlv = ObjectListView(self, wx.ID_ANY, style=wx.LC_REPORT|wx.SUNKEN_BORDER)
self.setBooks()
self.dataOlv.CreateCheckStateColumn()
# Allow the cell values to be edited when double-clicked
self.dataOlv.cellEditMode = ObjectListView.CELLEDIT_SINGLECLICK
# create an update button
updateBtn = wx.Button(self, wx.ID_ANY, "Update OLV")
updateBtn.Bind(wx.EVT_BUTTON, self.updateControl)
# Create some sizers
mainSizer = wx.BoxSizer(wx.VERTICAL)
mainSizer.Add(self.dataOlv, 1, wx.ALL|wx.EXPAND, 5)
mainSizer.Add(updateBtn, 0, wx.ALL|wx.CENTER, 5)
self.SetSizer(mainSizer)
#----------------------------------------------------------------------
def updateControl(self, event):
"""
"""
print "updating..."
product_dict = [Book("Core Python Programming", "Wesley Chun",
"0132269937", "Prentice Hall"),
Book("Python Programming for the Absolute Beginner",
"Michael Dawson", "1598631128", "Course Technology"),
Book("Learning Python", "Mark Lutz",
"0596513984", "O'Reilly")
]
data = self.products + product_dict
self.dataOlv.SetObjects(data)
#----------------------------------------------------------------------
def setBooks(self, data=None):
self.dataOlv.SetColumns([
ColumnDefn("Title", "left", 220, "title"),
ColumnDefn("Author", "left", 200, "author"),
ColumnDefn("ISBN", "right", 100, "isbn"),
ColumnDefn("Mfg", "left", 180, "mfg")
])
self.dataOlv.SetObjects(self.products)
########################################################################
class MainFrame(wx.Frame):
#----------------------------------------------------------------------
def __init__(self):
wx.Frame.__init__(self, parent=None, id=wx.ID_ANY,
title="ObjectListView Demo", size=(800,600))
panel = MainPanel(self)
########################################################################
class GenApp(wx.App):
#----------------------------------------------------------------------
def __init__(self, redirect=False, filename=None):
wx.App.__init__(self, redirect, filename)
#----------------------------------------------------------------------
def OnInit(self):
# create frame here
frame = MainFrame()
frame.Show()
return True
#----------------------------------------------------------------------
def main():
"""
Run the demo
"""
app = GenApp()
app.MainLoop()
if __name__ == "__main__":
main()
2 ответа:
Класс
ObjectListView
, по-видимому, не содержит этой функциональности. Покопавшись в коде некоторое время, я решил его расширить.Вы можете вывести свой собственный класс из
ObjectListView
и принудительно ввести событие. Вы должны переопределить методы_HandleLeftDownOnImage
иSetCheckState
. Или вы можете просто изменить код ObjectListView, если хотите. Я вывел новый класс:import wx.lib.newevent OvlCheckEvent, EVT_OVL_CHECK_EVENT = wx.lib.newevent.NewEvent() class MyOvl(ObjectListView): def SetCheckState(self, modelObject, state): """ This is the same code, just added the event inside """ if self.checkStateColumn is None: return None else: r = self.checkStateColumn.SetCheckState(modelObject, state) # Just added the event here =================================== e = OvlCheckEvent(object=modelObject, value=state) wx.PostEvent(self, e) # ============================================================= return r def _HandleLeftDownOnImage(self, rowIndex, subItemIndex): """ This is the same code, just added the event inside """ column = self.columns[subItemIndex] if not column.HasCheckState(): return self._PossibleFinishCellEdit() modelObject = self.GetObjectAt(rowIndex) if modelObject is not None: column.SetCheckState(modelObject, not column.GetCheckState(modelObject)) # Just added the event here =================================== e = OvlCheckEvent(object=modelObject, value=column.GetCheckState(modelObject)) wx.PostEvent(self, e) # ============================================================= self.RefreshIndex(rowIndex, modelObject)
Тогда я использовал этот класс вместо
ObjectListView
:self.dataOlv = MyOvl(self, wx.ID_ANY, style=wx.LC_REPORT|wx.SUNKEN_BORDER)
Связал событие:
self.dataOlv.Bind(EVT_OVL_CHECK_EVENT, self.HandleCheckbox)
И написал следующее: обработчик:
def HandleCheckbox(self, e): print(e.object.title, e.value)
Я уверен, что это не лучший способ, как это сделать, но это простой и эффективный Хак : - D.
Edit: полный пример
import wx import wx.lib.newevent from ObjectListView import ObjectListView, ColumnDefn, OLVEvent OvlCheckEvent, EVT_OVL_CHECK_EVENT = wx.lib.newevent.NewEvent() class MyOvl(ObjectListView): def SetCheckState(self, modelObject, state): """ This is the same code, just added the event inside """ if self.checkStateColumn is None: return None else: r = self.checkStateColumn.SetCheckState(modelObject, state) # Just added the event here =================================== e = OvlCheckEvent(object=modelObject, value=state) wx.PostEvent(self, e) # ============================================================= return r def _HandleLeftDownOnImage(self, rowIndex, subItemIndex): """ This is the same code, just added the event inside """ column = self.columns[subItemIndex] if not column.HasCheckState(): return self._PossibleFinishCellEdit() modelObject = self.GetObjectAt(rowIndex) if modelObject is not None: column.SetCheckState(modelObject, not column.GetCheckState(modelObject)) # Just added the event here =================================== e = OvlCheckEvent(object=modelObject, value=column.GetCheckState(modelObject)) wx.PostEvent(self, e) # ============================================================= self.RefreshIndex(rowIndex, modelObject) ######################################################################## class Book(object): """ Model of the Book object Contains the following attributes: 'ISBN', 'Author', 'Manufacturer', 'Title' """ #---------------------------------------------------------------------- def __init__(self, title, author, isbn, mfg): self.isbn = isbn self.author = author self.mfg = mfg self.title = title ######################################################################## class MainPanel(wx.Panel): #---------------------------------------------------------------------- def __init__(self, parent): wx.Panel.__init__(self, parent=parent, id=wx.ID_ANY) self.products = [Book("wxPython in Action", "Robin Dunn", "1932394621", "Manning"), Book("Hello World", "Warren and Carter Sande", "1933988495", "Manning") ] self.dataOlv = MyOvl(self, wx.ID_ANY, style=wx.LC_REPORT|wx.SUNKEN_BORDER) self.setBooks() self.dataOlv.CreateCheckStateColumn() self.dataOlv.Bind(EVT_OVL_CHECK_EVENT, self.HandleCheckbox) # Allow the cell values to be edited when double-clicked self.dataOlv.cellEditMode = ObjectListView.CELLEDIT_SINGLECLICK # create an update button updateBtn = wx.Button(self, wx.ID_ANY, "Update OLV") updateBtn.Bind(wx.EVT_BUTTON, self.updateControl) # Create some sizers mainSizer = wx.BoxSizer(wx.VERTICAL) mainSizer.Add(self.dataOlv, 1, wx.ALL|wx.EXPAND, 5) mainSizer.Add(updateBtn, 0, wx.ALL|wx.CENTER, 5) self.SetSizer(mainSizer) def HandleCheckbox(self, e): print(e.object.title, e.value) #---------------------------------------------------------------------- def updateControl(self, event): """ """ print "updating..." product_dict = [Book("Core Python Programming", "Wesley Chun", "0132269937", "Prentice Hall"), Book("Python Programming for the Absolute Beginner", "Michael Dawson", "1598631128", "Course Technology"), Book("Learning Python", "Mark Lutz", "0596513984", "O'Reilly") ] data = self.products + product_dict self.dataOlv.SetObjects(data) #---------------------------------------------------------------------- def setBooks(self, data=None): self.dataOlv.SetColumns([ ColumnDefn("Title", "left", 220, "title"), ColumnDefn("Author", "left", 200, "author"), ColumnDefn("ISBN", "right", 100, "isbn"), ColumnDefn("Mfg", "left", 180, "mfg") ]) self.dataOlv.SetObjects(self.products) ######################################################################## class MainFrame(wx.Frame): #---------------------------------------------------------------------- def __init__(self): wx.Frame.__init__(self, parent=None, id=wx.ID_ANY, title="ObjectListView Demo", size=(800,600)) panel = MainPanel(self) ######################################################################## class GenApp(wx.App): #---------------------------------------------------------------------- def __init__(self, redirect=False, filename=None): wx.App.__init__(self, redirect, filename) #---------------------------------------------------------------------- def OnInit(self): # create frame here frame = MainFrame() frame.Show() return True #---------------------------------------------------------------------- def main(): """ Run the demo """ app = GenApp() app.MainLoop() if __name__ == "__main__": main()
Документация ObjectListView, похоже, не содержит никаких данных по этому вопросу, кроме следующих двух списков:
Http://objectlistview.sourceforge.net/python/recipes.html#data-based-checkboxes
Первый из них может помочь вам с помощью параметра checkStateGetter. Я подозреваю, что ObjectListView включает в себя CheckListCtrlMixin. Если таким образом, вы можете подклассировать класс ObjectListView и переопределить метод OnCheckItem, как показано в демонстрационной версии wxPython для CheckListCtrlMixin.
Последняя мысль, которая у меня была, что вам, возможно, придется сделать привязку события adhoc, когда вы выбираете строку. Я имею в виду, что в событии выбора для строки попытайтесь получить объект события (надеюсь, экземпляр ListItem) и привязать этот объект к EVT_CHECKBOX.
Если ни один из них не работает, тогда переходите к официальной рассылке wxPython перечислите и спросите там. Именно там находится большинство пользователей wxPython.