Рубрики
Без рубрики

WxPython: добавление подсказок в ObjectListView

Эта статья описывает, как добавить подсказки на элементы в ObjectListView / listcctrl в инструментарии WXPYPHON GUI

Автор оригинала: 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 для выяснения этого.