Автор оригинала: Mike Driscoll.
Недавно я пытался выяснить, как добавить подсказки к каждому элементу в виджете ObjectListView в Wxpython в Windows. Wxpython Wiki Имеет пример, который использует Pywin32, но я не хотел идти этим путем. Поэтому я спросил в группе Google Google и получил интересную Ответ Отказ Они на самом деле использовали один из моих старого Статьи создать свое решение для меня. Я почистил его немного и решил, что стоит поделиться с моими читателями:
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() # 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) self.dataOlv.Bind(wx.EVT_LIST_ITEM_SELECTED, self.onSetToolTip) #---------------------------------------------------------------------- def updateControl(self, event): """ Update the control """ print "updating..." #product_dict = [{"title":"Core Python Programming", "author":"Wesley Chun", #"isbn":"0132269937", "mfg":"Prentice Hall"}, #{"title":"Python Programming for the Absolute Beginner", #"author":"Michael Dawson", "isbn":"1598631128", #"mfg":"Course Technology"}, #{"title":"Learning Python", "author":"Mark Lutz", #"isbn":"0596513984", "mfg":"O'Reilly"} #] product_list = [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_list self.dataOlv.SetObjects(data) #---------------------------------------------------------------------- def setBooks(self, data=None): """ Sets the book data for the OLV object """ 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) #---------------------------------------------------------------------- def onSetToolTip(self, event): """ Set the tool tip on the selected row """ item = self.dataOlv.GetSelectedObject() tooltip = "%s is a good writer!" % item.author event.GetEventObject().SetToolTipString(tooltip) event.Skip() ######################################################################## 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()
Все, что мне нужно было сделать, это добавить привязку к wx.evt_list_item_selected Отказ Затем в моем обработке событий мне нужно было схватить объект события и установить свою струнную строку. Что я бы очень хотел сделать, это найти способ скопировать это Рецепт сетки Так что я могу просто навестить на мышь на предметы и иметь изменение подсказки, но это не похоже на ObjectListView/listctrl имеет методы, которые мне нужно для перевода координат мыши в столбцу/строку. Несмотря на это, приведенное решение работает как рекламируется. Спасибо много, эрксин!
Обновление: Один из моих проницательных читателей заметил ошибку в моем коде, где, когда я нажал кнопку обновления, он добавил словарь к виджету объектаListView. Пока вы можете добавить словарь, это сломало Onsettooltip Метод как некоторые предметы, которые были добавлены, больше не были экземплярами книги. Поэтому я обновил код, чтобы добавить дополнительные элементы в качестве экземпляров книг и прокомментировали пример словаря.
Обновление (2013/12/30)
После игры с Ответ в Stackoverflow Я нашел, я обнаружил, что могу динамически обновлять всплывающую подсказку, хотя это все еще не совсем то, что я хотел бы. Но во-первых, вот обновленный код код:
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.dataOlv.Bind(wx.EVT_MOTION, self.updateTooltip) self.setBooks() # 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): """ Update the control """ print "updating..." #product_dict = [{"title":"Core Python Programming", "author":"Wesley Chun", #"isbn":"0132269937", "mfg":"Prentice Hall"}, #{"title":"Python Programming for the Absolute Beginner", #"author":"Michael Dawson", "isbn":"1598631128", #"mfg":"Course Technology"}, #{"title":"Learning Python", "author":"Mark Lutz", #"isbn":"0596513984", "mfg":"O'Reilly"} #] product_list = [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_list self.dataOlv.SetObjects(data) #---------------------------------------------------------------------- def setBooks(self, data=None): """ Sets the book data for the OLV object """ 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) #---------------------------------------------------------------------- def updateTooltip(self, event): """ Update the tooltip! """ pos = wx.GetMousePosition() mouse_pos = self.dataOlv.ScreenToClient(pos) item_index, flag = self.dataOlv.HitTest(mouse_pos) print flag if flag == wx.LIST_HITTEST_ONITEMLABEL: msg = "%s is a good book!" % self.dataOlv.GetItemText(item_index) self.dataOlv.SetToolTipString(msg) else: self.dataOlv.SetToolTipString("") event.Skip() ######################################################################## 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) #---------------------------------------------------------------------- def main(): """ Run the demo """ app = wx.App(False) frame = MainFrame() frame.Show() app.MainLoop() #---------------------------------------------------------------------- if __name__ == "__main__": main()
Основное изменение здесь состоит в том, чтобы удалить метод SELTOOLTIP и добавить метод UpdateTooltip. В указанном методе мы берем положение мыши и нам обновить всплывающую подсказку. Проблема у меня с таким подходом состоит в том, что подсказка только обновляет только при наведении мыши на ячейки в первом столбце. В противном случае это работает довольно хорошо. Если вы не знаете какой-то другой метод, чтобы сделать эту работу, дайте мне знать в комментариях.
Обновление (2014/01/23) :
Один из моих читателей связался со мной сегодня с другим исправлением к этому коду. Ему удалось выяснить, как добавить всплывающую подсказку, чтобы подсказку появилось не важно, какая часть ряда вы наведите курсор. Изменение очень просто. Изменение в Updatetooltip метод. Вот оригинальная версия:
def updateTooltip(self, event): """ Update the tooltip! """ pos = wx.GetMousePosition() mouse_pos = self.dataOlv.ScreenToClient(pos) item_index, flag = self.dataOlv.HitTest(mouse_pos) print flag if flag == wx.LIST_HITTEST_ONITEMLABEL: msg = "%s is a good book!" % self.dataOlv.GetItemText(item_index) self.dataOlv.SetToolTipString(msg) else: self.dataOlv.SetToolTipString("") event.Skip()
Вот фиксированная версия:
def updateTooltip(self, event): """ Update the tooltip! """ pos = wx.GetMousePosition() mouse_pos = self.dataOlv.ScreenToClient(pos) item_index, flag = self.dataOlv.HitTest(mouse_pos) print flag if item_index != -1: msg = "%s is a good book!" % self.dataOlv.GetItemText(item_index) self.dataOlv.SetToolTipString(msg) else: self.dataOlv.SetToolTipString("") event.Skip()
Изменение было только к Если заявление В этом мы сейчас смотрим на item_index Отказ Я на самом деле не знаю, почему это работает, но это делает для меня. Особая благодарность уходит в Mike Stover для выяснения этого.