在wx.ListCtrl中鼠标悬停时高亮显示列表项
我有一个叫 wxListCtrl 的控件,它可以显示一个包含信息的表格(有行和列)。通常情况下,只有当你用鼠标点击某一行时,那一行才会被高亮显示。但我想要的是,当我把鼠标移动到不同的行时,那一行也能自动高亮,而不需要点击鼠标。这样可以实现吗?
########################################################################
import wx
import sys, glob
class MyForm(wx.Frame):
#----------------------------------------------------------------------
def __init__(self):
wx.Frame.__init__(self, None, wx.ID_ANY, "List Control Tutorial")
# Add a panel so it looks the correct on all platforms
panel = wx.Panel(self, wx.ID_ANY)
self.index = 0
self.list_ctrl = wx.ListCtrl(panel, size=(-1,100),
style=wx.LC_REPORT
|wx.BORDER_SUNKEN
)
self.list_ctrl.InsertColumn(0, 'Subject')
self.list_ctrl.InsertColumn(1, 'Due')
self.list_ctrl.InsertColumn(2, 'Location', width=125)
self.list_ctrl.Bind(wx.EVT_ENTER_WINDOW, self.onMouseOver)
self.list_ctrl.Bind(wx.EVT_LEAVE_WINDOW, self.onMouseLeave)
btn = wx.Button(panel, label="Add Line")
btn.Bind(wx.EVT_BUTTON, self.add_line)
sizer = wx.BoxSizer(wx.VERTICAL)
sizer.Add(self.list_ctrl, 0, wx.ALL|wx.EXPAND, 5)
sizer.Add(btn, 0, wx.ALL|wx.CENTER, 5)
panel.SetSizer(sizer)
bmp = wx.Image("icon.bmp", wx.BITMAP_TYPE_BMP).ConvertToBitmap()
il = wx.ImageList(16,16)
il.Add(bmp)
self.list_ctrl.AssignImageList(il,wx.IMAGE_LIST_SMALL)
line = "Line %s" % self.index
self.list_ctrl.InsertStringItem(self.index, line,-1)
self.list_ctrl.SetStringItem(self.index, 1, "01/19/2010")
self.list_ctrl.SetStringItem(self.index, 2, "USA")
self.index += 1
self.list_ctrl.InsertStringItem(self.index, line,-1)
self.list_ctrl.SetStringItem(self.index, 1, "01/19/2010")
self.list_ctrl.SetStringItem(self.index, 2, "USA")
#self.list_ctrl.SetItemBackgroundColour(self.index,wx.LIGHT_GREY)
self.index += 1
self.list_ctrl.InsertStringItem(self.index, line,-1)
self.list_ctrl.SetStringItem(self.index, 1, "01/19/2010")
self.list_ctrl.SetStringItem(self.index, 2, "USA")
self.index += 1
#----------------------------------------------------------------------
def add_line(self, event):
if self.index > 0:
image = 1
else:
image = -1
line = "Line %s" % self.index
self.list_ctrl.InsertStringItem(self.index, line,image)
self.list_ctrl.SetStringItem(self.index, 1, "01/19/2010")
self.list_ctrl.SetStringItem(self.index, 2, "USA")
self.index += 1
def onMouseOver(self, event):
print "mouse over"
for item in range(self.list_ctrl.GetItemCount()):
self.list_ctrl.SetItemBackgroundColour(item,wx.NullColor)
x = event.GetX()
y = event.GetY()
item, flags = self.list_ctrl.HitTest((x, y))
self.list_ctrl.SetItemBackgroundColour(item,wx.RED)
#self.list_ctrl.RefreshItems(0,2)
event.Skip()
def onMouseLeave(self, event):
print "mouse leave"
for item in range(self.list_ctrl.GetItemCount()):
self.list_ctrl.SetItemBackgroundColour(item,wx.NullColor)
#self.list_ctrl.RefreshItems(0,2)
event.Skip()
'''
def onMouseOver(self, event): #USED to display tooltip on items that cannot be selected
x = event.GetX()
y = event.GetY()
item, flags = self.list_ctrl.HitTest((x, y))
color = self.list_ctrl.GetItemBackgroundColour(item)
if color == wx.NullColor:
self.list_ctrl.SetItemBackgroundColour(item,wx.RED)
elif color == wx.RED:
item = item - 1
color = self.list_ctrl.GetItemBackgroundColour(item)
self.list_ctrl.SetItemBackgroundColour(item,wx.Nu)
'''
#----------------------------------------------------------------------
# Run the program
if __name__ == "__main__":
app = wx.App(False)
frame = MyForm()
frame.Show()
app.MainLoop()
3 个回答
这件事一开始并不是“轻松”能做到的,但只要稍微动动脑筋,你应该能搞定。
你需要给你的 wxListCtrl 对象添加鼠标悬停和鼠标移出事件的监听器,然后每次鼠标悬停事件发生时,检查一下是哪个项目被鼠标指到了。如果你想的话,可以缓存列表项的坐标,但如果你滚动列表或者调整窗口大小,这样做可能会遇到问题。
这里有一些代码可以帮助你入门(这段代码没有经过测试,可能无法正常工作,你还需要把 MyListCtrl 加到合适的 wx.Frame 中):
import wx
class MyListCtrl(wx.ListCtrl):
def __init__(self, parent, id):
wx.ListCtrl.__init__(self, parent, id)
self.Bind(wx.EVT_ENTER_WINDOW, self.onMouseOver)
self.Bind(wx.EVT_LEAVE_WINDOW, self.onMouseLeave)
def onMouseOver(self, event):
#Loop through all items and set bgcolor to default, then:
item = self.HitTest(event.GetPosition())
self.SetItemBackgroundColour(item, 'Green')
self.RefreshItems()
event.Skip()
def onMouseLeave(self, event):
#Loop through all items and set bgcolor to default, then:
self.RefreshItems()
event.Skip()
我知道这个回复有点晚,但我用以下方法解决了问题: self.listCtrl.Bind(wx.EVT_MOTION, self.onMouseOver) 并且一开始把 self.previous_item 设置为 -1。
我用这个方法来高亮显示鼠标悬停的行,同时还可以改变提示信息。
def onMouseOver(self, event):
x = event.GetX()
y = event.GetY()
self.item, flags = self.listCtrl.HitTest((x, y))
if self.item < 0:
self.listCtrl.SetToolTipString("Colour codes Red - Loaded, Yellow - In Progress, Green - Finished, Blue - Invoiced, White - User defined")
return
if self.item != self.previous_item:
self.old_item = self.previous_item
self.previous_item = self.item
else:
return
bg_colour = self.listCtrl.GetItemBackgroundColour(self.item)
if bg_colour == wx.BLACK or bg_colour == wx.NullColour:
self.listCtrl.SetItemBackgroundColour(self.item,"#3246A8")
self.listCtrl.SetItemBackgroundColour(self.old_item,wx.BLACK)
elif bg_colour == "#3246A8":
self.listCtrl.SetItemBackgroundColour(self.item,wx.BLACK)
self.currentItem = self.item
rowid = self.listCtrl.GetItem(self.currentItem,13)
stat_test = rowid.GetText()
rowid = self.listCtrl.GetItem(self.currentItem,1)
file_test = rowid.GetText()
rowid = self.listCtrl.GetItem(self.currentItem,4)
running_test = rowid.GetText()
if stat_test == "0":
self.listCtrl.SetToolTipString("File currently playing\nRunning time "+running_test)
elif stat_test == "1":
self.listCtrl.SetToolTipString("In Progress\nRunning time "+running_test)
elif stat_test == "2":
self.listCtrl.SetToolTipString("Finished\nRunning time "+running_test)
elif stat_test == "3":
self.listCtrl.SetToolTipString("Invoiced\nRunning time "+running_test)
if file_test == self.file_playing and stat_test == "1":
self.listCtrl.SetToolTipString("File currently playing & In Progress\nRunning time "+running_test)
if file_test == self.file_playing and stat_test == "2":
self.listCtrl.SetToolTipString("File currently playing but Finished\nRunning time "+running_test)
if file_test == self.file_playing and stat_test == "3":
self.listCtrl.SetToolTipString("File currently playing but Invoiced\nRunning time "+running_test)
希望这对某些人有帮助。
我建议在创建列表控件(ListCtrl)时,先获取其中一个列表项(ListItem)的背景颜色,并把它存储到一个变量里:
self.defaultItemColor = someListItem.GetBackgroundColour()
然后用这个变量来改变颜色。调用列表项的设置方法后,有时候你还需要调用列表控件的 SetItem(listItem) 方法。出于某种原因,把背景设置为 NullColour 在列表控件中不起作用。我是在为我的一个应用程序创建深色模式时发现这个问题的。我其实在这里写过相关内容:http://www.blog.pythonlibrary.org/2011/11/05/wxpython-creating-a-dark-mode/