淡入淡出wxpython网格单元格的背景色

3 投票
2 回答
2692 浏览
提问于 2025-04-16 05:50

我有一个wxpython的网格控件,我想改变一个单元格的背景颜色,以显示它发生了一些变化。

我希望这个颜色变化能有渐变效果(就像浏览器里的JavaScript那样),这样看起来会更顺滑。这样做可以吗?

现在,我只是简单地改变背景颜色,然后在1.5秒后再把它改回来。

def do_stuf(self):
    # ... stuff ...
    wx.CallAfter(self.HighlightCell, row, col)

def HighlightCell(self, row, col):
    self.grid.Table.highlight = (row, col)
    self.grid.ForceRefresh()
    wx.CallLater(1500, self.ClearCellHighlight)

def ClearCellHighlight(self):
    self.grid.Table.highlight = None
    self.grid.ForceRefresh()

然后在虚拟表格中,我会检查这个单元格是否需要高亮显示:

def GetAttr(self, row, col, kind):
    """
    Use this callback to set the cell's background color
    """
    attr = wx.grid.GridCellAttr()
    if (row, col) == self.highlight:
        attr.SetBackgroundColour("green")
    elif row % 2:
        attr.SetBackgroundColour("white")
    else:
        attr.SetBackgroundColour("#e7ffff")

    return attr

另外,有没有其他好看的方法来表示一个单元格的内容已经改变了?

2 个回答

1

据我所知,你只能在框架小部件上设置透明度,这样就能看到它对所有子小部件的影响。我不太记得为什么单独设置每个小部件的透明度不行。不过,有个不错的方法可以模拟这种效果,就是使用一个叫做 wx.Timer 的定时器,它会循环显示一种颜色的不同深浅。当循环结束后,再把颜色恢复到正常的样子。这样就能很好地模拟出你想要的效果。

5

这是我之前做的一个小项目,目的是让列表中的项目在被删除时逐渐消失。你可以把代码保存为fade.py,然后运行它来查看演示效果。把这个功能改成适用于表格(Grid)也应该不难。

import wx

class FadeMixin(object):
    ''' FadeMixin provides one public method: DeleteItem. It is meant to
    be mixed in with a ListCtrl to 'fade out' items before they are
    really deleted. Mixin like this:

    Assumption: the background colour of the control is wx.WHITE

    class MyListCtrl(FadeMixin, wx.ListCtrl):
        ...
    '''
    def __init__(self, *args, **kwargs):
        self.__bgColour = wx.WHITE
        super(FadeMixin, self).__init__(*args, **kwargs)

    def DeleteItem(self, index, fadeStep=10, fadeSpeed=50):
        if self.IsEnabled():
            self.__startDeleteItem(index)
        fgColour, bgColour, transparentColour = self.__getColours(index)
        if fgColour == bgColour == transparentColour:
            self.__finishDeleteItem(index)
        else:
            for colour, setColour in [(fgColour, self.SetItemTextColour), 
                                      (bgColour, self.SetItemBackgroundColour)]:
                fadedColour = self.__fadeColour(colour, transparentColour, 
                                                fadeStep)
                setColour(index, fadedColour)
            wx.FutureCall(50, self.DeleteItem, index, fadeStep, fadeSpeed)

    def SetBackgroundColour(self, colour):
        self.__bgColour = colour
        super(FadeMixin, self).SetBackgroundColour(colour)

    def GetBackgroundColour(self):
        return self.__bgColour

    def __startDeleteItem(self, index):
        # Prevent user input during deletion. Things could get messy if
        # the user deletes another item when we're still busy fading out the 
        # first one:
        self.Disable()
        # Unselect the item that is to be deleted to make the fading visible:
        currentState = self.GetItemState(index, wx.LIST_STATE_SELECTED)
        self.SetItemState(index, ~currentState, wx.LIST_STATE_SELECTED)

    def __finishDeleteItem(self, index):
        super(FadeMixin, self).DeleteItem(index)
        self.Enable()

    def __getColours(self, index):
        fgColour = self.GetItemTextColour(index)
        bgColour = self.GetItemBackgroundColour(index)
        transparentColour = self.GetBackgroundColour()
        if not bgColour:
            bgColour = transparentColour
        return fgColour, bgColour, transparentColour

    def __fadeColour(self, colour, transparentColour, fadeStep):
        newColour = []
        for GetIntensity in wx.Colour.Red, wx.Colour.Green, wx.Colour.Blue:
            currentIntensity = GetIntensity(colour) 
            transparentIntensity = GetIntensity(transparentColour)
            if currentIntensity < transparentIntensity:
                newIntensity = min(transparentIntensity,
                                   currentIntensity + fadeStep)
            elif currentIntensity > transparentIntensity:
                newIntensity = max(transparentIntensity, 
                                currentIntensity - fadeStep)
            else:
                newIntensity = transparentIntensity
            newColour.append(newIntensity)
        return wx.Colour(*newColour)


class ListCtrl(FadeMixin, wx.ListCtrl):
    pass


class Frame(wx.Frame):
    def __init__(self, *args, **kwargs):
        super(Frame, self).__init__(*args, **kwargs)
        self.list = ListCtrl(self, style=wx.LC_REPORT)
        self.list.InsertColumn(0, 'Column 0')
        self.list.InsertColumn(1, 'Column 1')
        self.fillList()
        self.Bind(wx.EVT_LIST_ITEM_SELECTED, self.onSelected)
        self.Bind(wx.EVT_LIST_DELETE_ITEM, self.onDeleted)

    def onSelected(self, event):
        self.list.DeleteItem(event.GetIndex())

    def onDeleted(self, event):
        if self.list.GetItemCount() == 1:
            wx.CallAfter(self.fillList, False)

    def fillList(self, firstTime=True):
        for row in range(10):
            self.list.InsertStringItem(row, 'Item %d, Column 0'%row)
            self.list.SetStringItem(row, 1, 'Item %d, Column 1'%row)
        self.list.SetItemBackgroundColour(1, wx.BLUE)
        self.list.SetItemTextColour(2, wx.BLUE)
        self.list.SetItemBackgroundColour(3, wx.GREEN)
        self.list.SetItemTextColour(4, wx.GREEN)
        self.list.SetItemBackgroundColour(5, wx.RED)
        self.list.SetItemTextColour(6, wx.RED)
        self.list.SetItemBackgroundColour(7, wx.BLACK)
        self.list.SetItemTextColour(7, wx.WHITE)
        self.list.SetItemBackgroundColour(8, wx.WHITE)
        self.list.SetItemTextColour(8, wx.BLACK)
        if not firstTime:
            self.list.SetBackgroundColour(wx.BLUE)


app = wx.App(False)
frame = Frame(None, title='Select an item to fade it out')
frame.Show()
app.MainLoop()

撰写回答